aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFilippo Valsorda <filippo@golang.org>2018-06-29 13:16:42 -0400
committerFilippo Valsorda <filippo@golang.org>2018-07-03 15:17:00 -0400
commit77db076129160d50a098958c8e3f3fd5caa6257a (patch)
tree447493d9010d80a77353597dde156fb985680444
parentb77f5e4c8530279d40eb29dc86a320a8fb4f909e (diff)
parent1a27f048ad25f151d2a17ce7f2d73d0d2dbe94cf (diff)
downloadgo-77db076129160d50a098958c8e3f3fd5caa6257a.tar.gz
go-77db076129160d50a098958c8e3f3fd5caa6257a.zip
[dev.boringcrypto] all: merge master into dev.boringcrypto
Add a couple of skips for slow js/wasm tests. Change-Id: Ic95256b1d3c6e5e2f0cc536fad51e914d31cda9e
-rw-r--r--.github/SUPPORT.md2
-rw-r--r--api/except.txt11
-rw-r--r--api/go1.11.txt546
-rw-r--r--doc/code.html10
-rw-r--r--doc/contribute.html63
-rw-r--r--doc/debugging_with_gdb.html4
-rw-r--r--doc/diagnostics.html4
-rw-r--r--doc/docs.html2
-rw-r--r--doc/editors.html2
-rw-r--r--doc/gccgo_contribute.html6
-rw-r--r--doc/gccgo_install.html10
-rw-r--r--doc/go1.11.html346
-rw-r--r--doc/go1.2.html4
-rw-r--r--doc/go1.4.html10
-rw-r--r--doc/go1.6.html2
-rw-r--r--doc/go1.7.html2
-rw-r--r--doc/go_faq.html12
-rw-r--r--doc/go_spec.html10
-rw-r--r--doc/install-source.html8
-rw-r--r--doc/install.html39
-rw-r--r--doc/root.html2
-rwxr-xr-xlib/time/update.bash4
-rw-r--r--lib/time/zoneinfo.zipbin364985 -> 365101 bytes
-rw-r--r--misc/cgo/test/cgo_test.go1
-rw-r--r--misc/cgo/test/issue18146.go8
-rw-r--r--misc/cgo/test/issue23356.go19
-rw-r--r--misc/cgo/test/issue23555.go11
-rw-r--r--misc/cgo/test/issue23555a/a.go (renamed from src/syscall/time_js_wasm.s)11
-rw-r--r--misc/cgo/test/issue23555b/a.go12
-rw-r--r--misc/cgo/test/issue23720.go22
-rw-r--r--misc/cgo/test/issue9400/gccgo.go2
-rw-r--r--misc/cgo/test/issue9400/stubs.go2
-rw-r--r--misc/cgo/test/sigprocmask.c21
-rw-r--r--misc/cgo/testplugin/src/issue25756/main.go52
-rw-r--r--misc/cgo/testplugin/src/issue25756/plugin/c-life.c56
-rw-r--r--misc/cgo/testplugin/src/issue25756/plugin/life.go39
-rw-r--r--misc/cgo/testplugin/src/issue25756/plugin/life.h7
-rwxr-xr-xmisc/cgo/testplugin/test.bash11
-rw-r--r--misc/cgo/testsanitizers/tsan_test.go4
-rw-r--r--misc/cgo/testshared/src/trivial/trivial.go5
-rw-r--r--[-rwxr-xr-x]misc/wasm/wasm_exec.js232
-rw-r--r--src/archive/zip/struct.go10
-rw-r--r--src/bufio/scan.go19
-rw-r--r--src/cmd/asm/internal/arch/arm64.go3
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64.s2
-rw-r--r--src/cmd/cgo/doc.go25
-rw-r--r--src/cmd/cgo/main.go2
-rw-r--r--src/cmd/cgo/out.go22
-rw-r--r--src/cmd/compile/README.md2
-rw-r--r--src/cmd/compile/internal/arm64/ssa.go35
-rw-r--r--src/cmd/compile/internal/gc/bexport.go16
-rw-r--r--src/cmd/compile/internal/gc/bimport.go2
-rw-r--r--src/cmd/compile/internal/gc/builtin.go1
-rw-r--r--src/cmd/compile/internal/gc/builtin/runtime.go1
-rw-r--r--src/cmd/compile/internal/gc/const.go18
-rw-r--r--src/cmd/compile/internal/gc/esc.go91
-rw-r--r--src/cmd/compile/internal/gc/export.go4
-rw-r--r--src/cmd/compile/internal/gc/go.go1
-rw-r--r--src/cmd/compile/internal/gc/iexport.go16
-rw-r--r--src/cmd/compile/internal/gc/iimport.go4
-rw-r--r--src/cmd/compile/internal/gc/inl.go6
-rw-r--r--src/cmd/compile/internal/gc/main.go6
-rw-r--r--src/cmd/compile/internal/gc/noder.go4
-rw-r--r--src/cmd/compile/internal/gc/racewalk.go27
-rw-r--r--src/cmd/compile/internal/gc/select.go10
-rw-r--r--src/cmd/compile/internal/gc/ssa.go52
-rw-r--r--src/cmd/compile/internal/gc/swt.go5
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go76
-rw-r--r--src/cmd/compile/internal/gc/walk.go5
-rw-r--r--src/cmd/compile/internal/ssa/compile.go4
-rw-r--r--src/cmd/compile/internal/ssa/gen/AMD64Ops.go4
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM.rules10
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64.rules8
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64Ops.go19
-rw-r--r--src/cmd/compile/internal/ssa/gen/Wasm.rules5
-rw-r--r--src/cmd/compile/internal/ssa/gen/WasmOps.go2
-rw-r--r--src/cmd/compile/internal/ssa/gen/genericOps.go7
-rw-r--r--src/cmd/compile/internal/ssa/html.go120
-rw-r--r--src/cmd/compile/internal/ssa/loopbce.go6
-rw-r--r--src/cmd/compile/internal/ssa/opGen.go86
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM.go20
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go66
-rw-r--r--src/cmd/compile/internal/ssa/rewriteWasm.go21
-rw-r--r--src/cmd/compile/internal/ssa/schedule.go22
-rw-r--r--src/cmd/compile/internal/types/scope.go13
-rw-r--r--src/cmd/compile/internal/wasm/ssa.go16
-rw-r--r--src/cmd/cover/cover_test.go34
-rw-r--r--src/cmd/dist/build.go2
-rw-r--r--src/cmd/dist/buildtool.go2
-rw-r--r--src/cmd/dist/test.go43
-rw-r--r--src/cmd/doc/doc_test.go20
-rw-r--r--src/cmd/doc/main.go29
-rw-r--r--src/cmd/doc/testdata/nested/ignore.go4
-rw-r--r--src/cmd/doc/testdata/nested/nested/real.go4
-rw-r--r--src/cmd/go/alldocs.go11
-rw-r--r--src/cmd/go/go_test.go39
-rw-r--r--src/cmd/go/internal/cache/cache.go15
-rw-r--r--src/cmd/go/internal/cfg/cfg.go12
-rw-r--r--src/cmd/go/internal/dirhash/hash.go103
-rw-r--r--src/cmd/go/internal/dirhash/hash_test.go135
-rw-r--r--src/cmd/go/internal/envcmd/env.go3
-rw-r--r--src/cmd/go/internal/fix/fix.go11
-rw-r--r--src/cmd/go/internal/fmtcmd/fmt.go10
-rw-r--r--src/cmd/go/internal/generate/generate.go16
-rw-r--r--src/cmd/go/internal/get/get.go16
-rw-r--r--src/cmd/go/internal/help/help.go2
-rw-r--r--src/cmd/go/internal/help/helpdoc.go1
-rw-r--r--src/cmd/go/internal/imports/build.go211
-rw-r--r--src/cmd/go/internal/imports/read.go249
-rw-r--r--src/cmd/go/internal/imports/read_test.go228
-rw-r--r--src/cmd/go/internal/imports/scan.go82
-rw-r--r--src/cmd/go/internal/imports/scan_test.go67
-rw-r--r--src/cmd/go/internal/imports/tags.go35
-rw-r--r--src/cmd/go/internal/imports/testdata/import1/x.go3
-rw-r--r--src/cmd/go/internal/imports/testdata/import1/x1.go9
-rw-r--r--src/cmd/go/internal/imports/testdata/import1/x_darwin.go3
-rw-r--r--src/cmd/go/internal/imports/testdata/import1/x_windows.go3
-rw-r--r--src/cmd/go/internal/list/list.go3
-rw-r--r--src/cmd/go/internal/load/path.go16
-rw-r--r--src/cmd/go/internal/load/pkg.go98
-rw-r--r--src/cmd/go/internal/load/search.go338
-rw-r--r--src/cmd/go/internal/modconv/dep.go71
-rw-r--r--src/cmd/go/internal/modconv/glide.go40
-rw-r--r--src/cmd/go/internal/modconv/glock.go23
-rw-r--r--src/cmd/go/internal/modconv/godeps.go29
-rw-r--r--src/cmd/go/internal/modconv/modconv.go25
-rw-r--r--src/cmd/go/internal/modconv/modconv_test.go69
-rw-r--r--src/cmd/go/internal/modconv/testdata/cockroach.glock41
-rw-r--r--src/cmd/go/internal/modconv/testdata/cockroach.out31
-rw-r--r--src/cmd/go/internal/modconv/testdata/dockermachine.godeps159
-rw-r--r--src/cmd/go/internal/modconv/testdata/dockermachine.out33
-rw-r--r--src/cmd/go/internal/modconv/testdata/dockerman.glide52
-rw-r--r--src/cmd/go/internal/modconv/testdata/dockerman.out16
-rw-r--r--src/cmd/go/internal/modconv/testdata/govmomi.out5
-rw-r--r--src/cmd/go/internal/modconv/testdata/govmomi.vmanifest46
-rw-r--r--src/cmd/go/internal/modconv/testdata/juju.out106
-rw-r--r--src/cmd/go/internal/modconv/testdata/juju.tsv106
-rw-r--r--src/cmd/go/internal/modconv/testdata/moby.out105
-rw-r--r--src/cmd/go/internal/modconv/testdata/moby.vconf149
-rw-r--r--src/cmd/go/internal/modconv/testdata/panicparse.out8
-rw-r--r--src/cmd/go/internal/modconv/testdata/panicparse.vyml17
-rw-r--r--src/cmd/go/internal/modconv/testdata/prometheus.out258
-rw-r--r--src/cmd/go/internal/modconv/testdata/prometheus.vjson1605
-rw-r--r--src/cmd/go/internal/modconv/testdata/upspin.dep57
-rw-r--r--src/cmd/go/internal/modconv/testdata/upspin.out8
-rw-r--r--src/cmd/go/internal/modconv/tsv.go23
-rw-r--r--src/cmd/go/internal/modconv/vconf.go26
-rw-r--r--src/cmd/go/internal/modconv/vjson.go28
-rw-r--r--src/cmd/go/internal/modconv/vmanifest.go28
-rw-r--r--src/cmd/go/internal/modconv/vyml.go40
-rw-r--r--src/cmd/go/internal/modfetch/bitbucket/fetch.go22
-rw-r--r--src/cmd/go/internal/modfetch/codehost/codehost.go187
-rw-r--r--src/cmd/go/internal/modfetch/coderepo.go576
-rw-r--r--src/cmd/go/internal/modfetch/coderepo_test.go688
-rw-r--r--src/cmd/go/internal/modfetch/convert.go78
-rw-r--r--src/cmd/go/internal/modfetch/convert_test.go139
-rw-r--r--src/cmd/go/internal/modfetch/domain.go178
-rw-r--r--src/cmd/go/internal/modfetch/github/fetch.go24
-rw-r--r--src/cmd/go/internal/modfetch/gitrepo/fetch.go445
-rw-r--r--src/cmd/go/internal/modfetch/gitrepo/fetch_test.go500
-rw-r--r--src/cmd/go/internal/modfetch/googlesource/fetch.go25
-rw-r--r--src/cmd/go/internal/modfetch/gopkgin.go22
-rw-r--r--src/cmd/go/internal/modfetch/noweb.go24
-rw-r--r--src/cmd/go/internal/modfetch/proxy.go164
-rw-r--r--src/cmd/go/internal/modfetch/query.go84
-rw-r--r--src/cmd/go/internal/modfetch/repo.go137
-rw-r--r--src/cmd/go/internal/modfetch/unzip.go100
-rw-r--r--src/cmd/go/internal/modfetch/web.go31
-rw-r--r--src/cmd/go/internal/modfile/gopkgin.go47
-rw-r--r--src/cmd/go/internal/modfile/print.go164
-rw-r--r--src/cmd/go/internal/modfile/read.go699
-rw-r--r--src/cmd/go/internal/modfile/read_test.go306
-rw-r--r--src/cmd/go/internal/modfile/rule.go507
-rw-r--r--src/cmd/go/internal/modfile/testdata/block.golden29
-rw-r--r--src/cmd/go/internal/modfile/testdata/block.in29
-rw-r--r--src/cmd/go/internal/modfile/testdata/comment.golden10
-rw-r--r--src/cmd/go/internal/modfile/testdata/comment.in8
-rw-r--r--src/cmd/go/internal/modfile/testdata/empty.golden0
-rw-r--r--src/cmd/go/internal/modfile/testdata/empty.in0
-rw-r--r--src/cmd/go/internal/modfile/testdata/gopkg.in.golden6
-rw-r--r--src/cmd/go/internal/modfile/testdata/module.golden1
-rw-r--r--src/cmd/go/internal/modfile/testdata/module.in1
-rw-r--r--src/cmd/go/internal/modfile/testdata/replace.golden5
-rw-r--r--src/cmd/go/internal/modfile/testdata/replace.in5
-rw-r--r--src/cmd/go/internal/modfile/testdata/replace2.golden8
-rw-r--r--src/cmd/go/internal/modfile/testdata/replace2.in8
-rw-r--r--src/cmd/go/internal/modfile/testdata/rule1.golden7
-rw-r--r--src/cmd/go/internal/modinfo/info.go11
-rw-r--r--src/cmd/go/internal/module/module.go195
-rw-r--r--src/cmd/go/internal/module/module_test.go184
-rw-r--r--src/cmd/go/internal/mvs/mvs.go308
-rw-r--r--src/cmd/go/internal/mvs/mvs_test.go377
-rw-r--r--src/cmd/go/internal/search/search.go423
-rw-r--r--src/cmd/go/internal/search/search_test.go (renamed from src/cmd/go/internal/load/match_test.go)10
-rw-r--r--src/cmd/go/internal/semver/semver.go351
-rw-r--r--src/cmd/go/internal/semver/semver_test.go123
-rw-r--r--src/cmd/go/internal/vet/vetflag.go2
-rw-r--r--src/cmd/go/internal/vgo/build.go115
-rw-r--r--src/cmd/go/internal/vgo/fetch.go232
-rw-r--r--src/cmd/go/internal/vgo/get.go152
-rw-r--r--src/cmd/go/internal/vgo/init.go411
-rw-r--r--src/cmd/go/internal/vgo/list.go153
-rw-r--r--src/cmd/go/internal/vgo/load.go575
-rw-r--r--src/cmd/go/internal/vgo/search.go196
-rw-r--r--src/cmd/go/internal/vgo/vendor.go156
-rw-r--r--src/cmd/go/internal/vgo/verify.go104
-rw-r--r--src/cmd/go/internal/web2/web.go297
-rw-r--r--src/cmd/go/internal/web2/web_test.go35
-rw-r--r--src/cmd/go/internal/webtest/test.go314
-rw-r--r--src/cmd/go/internal/work/action.go31
-rw-r--r--src/cmd/go/internal/work/build.go3
-rw-r--r--src/cmd/go/internal/work/buildid.go55
-rw-r--r--src/cmd/go/internal/work/exec.go91
-rw-r--r--src/cmd/go/internal/work/init.go13
-rw-r--r--src/cmd/go/testdata/badmod/go.mod1
-rw-r--r--src/cmd/go/testdata/badmod/x.go4
-rw-r--r--src/cmd/go/testdata/src/vetfail/p1/p1.go2
-rw-r--r--src/cmd/go/testdata/vendormod/go.mod16
-rw-r--r--src/cmd/go/testdata/vendormod/v1.go3
-rw-r--r--src/cmd/go/testdata/vendormod/v2.go5
-rw-r--r--src/cmd/go/testdata/vendormod/v3.go5
-rw-r--r--src/cmd/go/testdata/vendormod/w/go.mod1
-rw-r--r--src/cmd/go/testdata/vendormod/w/w.go1
-rw-r--r--src/cmd/go/testdata/vendormod/x/go.mod1
-rw-r--r--src/cmd/go/testdata/vendormod/x/x.go1
-rw-r--r--src/cmd/go/testdata/vendormod/y/go.mod1
-rw-r--r--src/cmd/go/testdata/vendormod/y/y.go1
-rw-r--r--src/cmd/go/testdata/vendormod/z/go.mod1
-rw-r--r--src/cmd/go/testdata/vendormod/z/z.go1
-rw-r--r--src/cmd/internal/obj/arm64/a.out.go2
-rw-r--r--src/cmd/internal/obj/arm64/anames.go2
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go12
-rw-r--r--src/cmd/internal/obj/ppc64/obj9.go16
-rw-r--r--src/cmd/internal/obj/wasm/a.out.go3
-rw-r--r--src/cmd/internal/obj/wasm/anames.go1
-rw-r--r--src/cmd/internal/obj/wasm/wasmobj.go16
-rw-r--r--src/cmd/link/doc.go4
-rw-r--r--src/cmd/link/internal/ld/config.go7
-rw-r--r--src/cmd/link/internal/ld/data.go126
-rw-r--r--src/cmd/link/internal/ld/dwarf.go86
-rw-r--r--src/cmd/link/internal/ld/elf.go2
-rw-r--r--src/cmd/link/internal/ld/lib.go40
-rw-r--r--src/cmd/link/internal/ld/link.go7
-rw-r--r--src/cmd/link/internal/ld/macho.go77
-rw-r--r--src/cmd/link/internal/ld/macho_combine_dwarf.go155
-rw-r--r--src/cmd/link/internal/ld/main.go5
-rw-r--r--src/cmd/link/internal/ld/pcln.go7
-rw-r--r--src/cmd/link/internal/ld/pe.go58
-rw-r--r--src/cmd/link/internal/ld/symtab.go38
-rw-r--r--src/cmd/link/internal/wasm/asm.go22
-rw-r--r--src/cmd/nm/nm_test.go22
-rw-r--r--src/cmd/trace/annotations.go4
-rw-r--r--src/cmd/trace/annotations_test.go6
-rw-r--r--src/cmd/trace/trace_test.go2
-rw-r--r--src/cmd/vet/all/main.go6
-rw-r--r--src/cmd/vet/all/whitelist/darwin_386.txt1
-rw-r--r--src/cmd/vet/all/whitelist/darwin_arm.txt6
-rw-r--r--src/cmd/vet/all/whitelist/darwin_arm64.txt2
-rw-r--r--src/cmd/vet/all/whitelist/linux_ppc64x.txt1
-rw-r--r--src/cmd/vet/all/whitelist/s390x.txt7
-rw-r--r--src/cmd/vet/all/whitelist/wasm.txt28
-rw-r--r--src/cmd/vet/asmdecl.go6
-rw-r--r--src/cmd/vet/bool.go25
-rw-r--r--src/cmd/vet/buildtag.go23
-rw-r--r--src/cmd/vet/doc.go27
-rw-r--r--src/cmd/vet/main.go110
-rw-r--r--src/cmd/vet/print.go375
-rw-r--r--src/cmd/vet/testdata/buildtag/buildtag.go2
-rw-r--r--src/cmd/vet/testdata/print.go71
-rw-r--r--src/context/example_test.go2
-rw-r--r--src/crypto/aes/aes_gcm.go15
-rw-r--r--src/crypto/aes/cbc_s390x.go4
-rw-r--r--src/crypto/aes/cipher.go7
-rw-r--r--src/crypto/aes/cipher_amd64.go7
-rw-r--r--src/crypto/aes/cipher_arm64.go7
-rw-r--r--src/crypto/aes/cipher_ppc64le.go7
-rw-r--r--src/crypto/aes/cipher_s390x.go18
-rw-r--r--src/crypto/aes/ctr_s390x.go9
-rw-r--r--src/crypto/aes/gcm_s390x.go31
-rw-r--r--src/crypto/cipher/cbc.go8
-rw-r--r--src/crypto/cipher/cfb.go8
-rw-r--r--src/crypto/cipher/ctr.go8
-rw-r--r--src/crypto/cipher/gcm.go23
-rw-r--r--src/crypto/cipher/ofb.go8
-rw-r--r--src/crypto/des/cipher.go47
-rw-r--r--src/crypto/internal/subtle/aliasing.go34
-rw-r--r--src/crypto/internal/subtle/aliasing_appengine.go37
-rw-r--r--src/crypto/internal/subtle/aliasing_test.go50
-rw-r--r--src/crypto/rand/rand.go4
-rw-r--r--src/crypto/rand/rand_js.go6
-rw-r--r--src/crypto/rc4/rc4.go8
-rw-r--r--src/crypto/rc4/rc4_asm.go10
-rw-r--r--src/crypto/rsa/boring_test.go6
-rw-r--r--src/crypto/sha1/sha1block_s390x.go7
-rw-r--r--src/crypto/sha1/sha1block_s390x.s34
-rw-r--r--src/crypto/sha256/sha256block_s390x.go7
-rw-r--r--src/crypto/sha256/sha256block_s390x.s34
-rw-r--r--src/crypto/sha512/sha512block_s390x.go7
-rw-r--r--src/crypto/sha512/sha512block_s390x.s34
-rw-r--r--src/crypto/tls/auth.go108
-rw-r--r--src/crypto/tls/auth_test.go101
-rw-r--r--src/crypto/tls/boring_test.go4
-rw-r--r--src/crypto/tls/cipher_suites.go4
-rw-r--r--src/crypto/tls/common.go15
-rw-r--r--src/crypto/tls/handshake_client.go26
-rw-r--r--src/crypto/tls/handshake_client_test.go39
-rw-r--r--src/crypto/tls/handshake_server.go59
-rw-r--r--src/crypto/tls/key_agreement.go140
-rw-r--r--src/crypto/tls/prf.go33
-rw-r--r--src/crypto/x509/root_darwin.go4
-rw-r--r--src/crypto/x509/root_darwin_test.go5
-rw-r--r--src/debug/elf/file.go41
-rw-r--r--src/debug/macho/file.go82
-rw-r--r--src/debug/pe/file.go91
-rw-r--r--src/encoding/base32/base32.go26
-rw-r--r--src/encoding/gob/encoder_test.go2
-rw-r--r--src/flag/example_value_test.go44
-rw-r--r--src/flag/flag.go3
-rw-r--r--src/go/ast/ast.go8
-rw-r--r--src/go/build/deps_test.go124
-rw-r--r--src/go/doc/example.go122
-rw-r--r--src/go/doc/example_test.go114
-rw-r--r--src/go/doc/reader.go8
-rw-r--r--src/go/doc/testdata/issue22856.0.golden (renamed from src/go/doc/testdata/issue18063.0.golden)18
-rw-r--r--src/go/doc/testdata/issue22856.1.golden (renamed from src/go/doc/testdata/issue18063.1.golden)18
-rw-r--r--src/go/doc/testdata/issue22856.2.golden (renamed from src/go/doc/testdata/issue18063.2.golden)18
-rw-r--r--src/go/doc/testdata/issue22856.go (renamed from src/go/doc/testdata/issue18063.go)12
-rw-r--r--src/go/internal/gccgoimporter/ar.go148
-rw-r--r--src/go/internal/gccgoimporter/importer.go50
-rw-r--r--src/go/internal/gccgoimporter/importer_test.go1
-rw-r--r--src/go/internal/gccgoimporter/parser.go9
-rw-r--r--src/go/internal/gccgoimporter/testdata/libimportsar.abin0 -> 9302 bytes
-rw-r--r--src/go/internal/gcimporter/bimport.go29
-rw-r--r--src/go/internal/gcimporter/gcimporter.go21
-rw-r--r--src/go/internal/gcimporter/gcimporter_test.go12
-rw-r--r--src/go/internal/gcimporter/iimport.go21
-rw-r--r--src/go/internal/gcimporter/testdata/versions/test.go5
-rw-r--r--src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.abin0 -> 2420 bytes
-rw-r--r--src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.abin0 -> 2426 bytes
-rw-r--r--src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.abin0 -> 2600 bytes
-rw-r--r--src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.abin0 -> 2420 bytes
-rw-r--r--src/go/types/sizes.go3
-rw-r--r--src/go/types/type.go16
-rw-r--r--src/go/types/typestring_test.go26
-rw-r--r--src/go/types/universe.go2
-rw-r--r--src/html/template/escape.go2
-rw-r--r--src/internal/bytealg/compare_wasm.s24
-rw-r--r--src/internal/bytealg/indexbyte_wasm.s20
-rw-r--r--src/internal/cpu/cpu.go26
-rw-r--r--src/internal/cpu/cpu_no_init.go1
-rw-r--r--src/internal/cpu/cpu_s390x.go157
-rw-r--r--src/internal/cpu/cpu_s390x.s122
-rw-r--r--src/internal/cpu/cpu_s390x_test.go63
-rw-r--r--src/internal/poll/fd_mutex.go10
-rw-r--r--src/internal/poll/fd_mutex_test.go22
-rw-r--r--src/internal/poll/fd_unix.go54
-rw-r--r--src/internal/poll/sendfile_windows.go10
-rw-r--r--src/internal/poll/splice_linux.go28
-rw-r--r--src/internal/syscall/unix/nonblocking_js.go2
-rw-r--r--src/internal/syscall/windows/registry/zsyscall_windows.go2
-rw-r--r--src/internal/syscall/windows/zsyscall_windows.go2
-rwxr-xr-xsrc/make.bash2
-rw-r--r--src/math/big/float.go8
-rw-r--r--src/math/big/float_test.go25
-rw-r--r--src/math/big/int.go16
-rw-r--r--src/math/big/int_test.go2
-rw-r--r--src/math/example_test.go24
-rw-r--r--src/mime/multipart/formdata.go2
-rw-r--r--src/mime/multipart/formdata_test.go7
-rw-r--r--src/mime/multipart/multipart.go14
-rw-r--r--src/mime/multipart/multipart_test.go8
-rw-r--r--src/mime/quotedprintable/reader.go4
-rw-r--r--src/mime/quotedprintable/reader_test.go4
-rw-r--r--src/mime/type.go3
-rw-r--r--src/net/cgo_unix.go2
-rw-r--r--src/net/dnsconfig_unix.go2
-rw-r--r--src/net/example_test.go5
-rw-r--r--src/net/fd_unix.go42
-rw-r--r--src/net/fd_windows.go2
-rw-r--r--src/net/file_test.go54
-rw-r--r--src/net/file_unix.go5
-rw-r--r--src/net/hosts.go2
-rw-r--r--src/net/http/export_test.go4
-rw-r--r--src/net/http/header.go19
-rw-r--r--src/net/http/httptest/recorder.go6
-rw-r--r--src/net/http/httptrace/trace.go14
-rw-r--r--src/net/http/request.go22
-rw-r--r--src/net/http/response.go4
-rw-r--r--src/net/http/roundtrip_js.go38
-rw-r--r--src/net/http/serve_test.go119
-rw-r--r--src/net/http/server.go78
-rw-r--r--src/net/http/sniff.go2
-rw-r--r--src/net/http/sniff_test.go1
-rw-r--r--src/net/http/transfer.go17
-rw-r--r--src/net/http/transfer_test.go2
-rw-r--r--src/net/http/transport.go56
-rw-r--r--src/net/http/transport_test.go113
-rw-r--r--src/net/ip.go60
-rw-r--r--src/net/ipsock.go28
-rw-r--r--src/net/lookup.go32
-rw-r--r--src/net/lookup_fake.go6
-rw-r--r--src/net/lookup_plan9.go6
-rw-r--r--src/net/lookup_test.go83
-rw-r--r--src/net/lookup_unix.go25
-rw-r--r--src/net/lookup_windows.go6
-rw-r--r--src/net/net.go8
-rw-r--r--src/net/net_fake.go2
-rw-r--r--src/net/sendfile_test.go59
-rw-r--r--src/net/sendfile_unix_alt.go6
-rw-r--r--src/net/splice_test.go63
-rw-r--r--src/os/fifo_test.go112
-rw-r--r--src/os/file.go15
-rw-r--r--src/os/file_unix.go15
-rw-r--r--src/os/path.go61
-rw-r--r--src/os/pipe_test.go90
-rwxr-xr-xsrc/race.bash4
-rw-r--r--src/reflect/all_test.go88
-rw-r--r--src/reflect/type.go34
-rw-r--r--src/regexp/example_test.go6
-rw-r--r--src/regexp/regexp.go4
-rw-r--r--src/runtime/asm_arm.s71
-rw-r--r--src/runtime/asm_arm64.s34
-rw-r--r--src/runtime/asm_ppc64x.s16
-rw-r--r--src/runtime/asm_wasm.s4
-rw-r--r--src/runtime/defs_darwin.go55
-rw-r--r--src/runtime/defs_darwin_386.go96
-rw-r--r--src/runtime/defs_darwin_amd64.go97
-rw-r--r--src/runtime/defs_darwin_arm.go96
-rw-r--r--src/runtime/defs_darwin_arm64.go96
-rw-r--r--src/runtime/iface.go2
-rw-r--r--src/runtime/internal/atomic/bench_test.go20
-rw-r--r--src/runtime/internal/sys/arch.go2
-rw-r--r--src/runtime/internal/sys/arch_wasm.go2
-rw-r--r--src/runtime/lock_futex.go6
-rw-r--r--src/runtime/lock_js.go125
-rw-r--r--src/runtime/lock_sema.go6
-rw-r--r--src/runtime/map.go15
-rw-r--r--src/runtime/map_fast32.go5
-rw-r--r--src/runtime/map_fast64.go5
-rw-r--r--src/runtime/map_faststr.go5
-rw-r--r--src/runtime/map_test.go96
-rw-r--r--src/runtime/memclr_386.s2
-rw-r--r--src/runtime/memclr_amd64.s2
-rw-r--r--src/runtime/memmove_386.s2
-rw-r--r--src/runtime/memmove_amd64.s3
-rw-r--r--src/runtime/netpoll_kqueue.go6
-rw-r--r--src/runtime/os_darwin.go359
-rw-r--r--src/runtime/os_dragonfly.go6
-rw-r--r--src/runtime/os_freebsd.go6
-rw-r--r--src/runtime/os_netbsd.go6
-rw-r--r--src/runtime/os_openbsd.go6
-rw-r--r--src/runtime/panic.go6
-rw-r--r--src/runtime/pprof/proto.go65
-rw-r--r--src/runtime/pprof/proto_test.go76
-rw-r--r--src/runtime/pprof/testdata/mappingtest/main.go105
-rw-r--r--src/runtime/proc.go14
-rw-r--r--src/runtime/race.go1
-rw-r--r--src/runtime/race/race.go2
-rw-r--r--src/runtime/race_ppc64le.s568
-rw-r--r--src/runtime/rt0_darwin_arm64.s40
-rw-r--r--src/runtime/rt0_js_wasm.s78
-rw-r--r--src/runtime/runtime-gdb_test.go3
-rw-r--r--src/runtime/runtime-lldb_test.go14
-rw-r--r--src/runtime/runtime2.go3
-rw-r--r--src/runtime/stack.go6
-rw-r--r--src/runtime/sys_darwin.go143
-rw-r--r--src/runtime/sys_darwin_386.s433
-rw-r--r--src/runtime/sys_darwin_amd64.s388
-rw-r--r--src/runtime/sys_darwin_arm.s364
-rw-r--r--src/runtime/sys_darwin_arm64.s400
-rw-r--r--src/runtime/sys_wasm.s15
-rw-r--r--src/runtime/testdata/testprog/numcpu_freebsd.go13
-rw-r--r--src/runtime/tls_ppc64x.s2
-rw-r--r--src/runtime/trace/trace.go4
-rw-r--r--src/runtime/vlrt.go1
-rw-r--r--src/strconv/atob.go2
-rw-r--r--src/sync/rwmutex.go1
-rw-r--r--src/syscall/asm_darwin_amd64.s2
-rw-r--r--src/syscall/fs_js.go20
-rw-r--r--src/syscall/js/callback.go147
-rw-r--r--src/syscall/js/js.go233
-rw-r--r--src/syscall/js/js_js.s42
-rw-r--r--src/syscall/js/js_test.go124
-rw-r--r--src/syscall/js/typedarray.go103
-rwxr-xr-xsrc/syscall/mkall.sh30
-rwxr-xr-xsrc/syscall/mkerrors.sh2
-rwxr-xr-xsrc/syscall/mksyscall.pl2
-rwxr-xr-xsrc/syscall/mksyscall_solaris.pl2
-rw-r--r--src/syscall/mksyscall_windows.go2
-rwxr-xr-xsrc/syscall/mksysctl_openbsd.pl2
-rwxr-xr-xsrc/syscall/mksysnum_darwin.pl2
-rwxr-xr-xsrc/syscall/mksysnum_dragonfly.pl2
-rwxr-xr-xsrc/syscall/mksysnum_freebsd.pl2
-rwxr-xr-xsrc/syscall/mksysnum_linux.pl2
-rwxr-xr-xsrc/syscall/mksysnum_netbsd.pl2
-rwxr-xr-xsrc/syscall/mksysnum_openbsd.pl2
-rwxr-xr-xsrc/syscall/mksysnum_plan9.sh2
-rw-r--r--src/syscall/net_js.go7
-rw-r--r--src/syscall/security_windows.go4
-rw-r--r--src/syscall/syscall_linux.go27
-rw-r--r--src/syscall/syscall_linux_test.go94
-rw-r--r--src/syscall/syscall_windows_test.go6
-rw-r--r--src/syscall/types_linux.go1
-rw-r--r--src/syscall/zerrors_darwin_386.go2
-rw-r--r--src/syscall/zerrors_darwin_amd64.go2
-rw-r--r--src/syscall/zerrors_darwin_arm.go2
-rw-r--r--src/syscall/zerrors_darwin_arm64.go2
-rw-r--r--src/syscall/zerrors_dragonfly_amd64.go2
-rw-r--r--src/syscall/zerrors_freebsd_386.go2
-rw-r--r--src/syscall/zerrors_freebsd_amd64.go2
-rw-r--r--src/syscall/zerrors_freebsd_arm.go2
-rw-r--r--src/syscall/zerrors_linux_386.go2
-rw-r--r--src/syscall/zerrors_linux_amd64.go2
-rw-r--r--src/syscall/zerrors_linux_arm.go2
-rw-r--r--src/syscall/zerrors_linux_arm64.go2
-rw-r--r--src/syscall/zerrors_linux_mips.go2
-rw-r--r--src/syscall/zerrors_linux_mips64.go2
-rw-r--r--src/syscall/zerrors_linux_mips64le.go2
-rw-r--r--src/syscall/zerrors_linux_mipsle.go2
-rw-r--r--src/syscall/zerrors_linux_ppc64.go2
-rw-r--r--src/syscall/zerrors_linux_ppc64le.go2
-rw-r--r--src/syscall/zerrors_linux_s390x.go2
-rw-r--r--src/syscall/zerrors_netbsd_386.go2
-rw-r--r--src/syscall/zerrors_netbsd_amd64.go2
-rw-r--r--src/syscall/zerrors_netbsd_arm.go2
-rw-r--r--src/syscall/zerrors_openbsd_386.go2
-rw-r--r--src/syscall/zerrors_openbsd_amd64.go2
-rw-r--r--src/syscall/zerrors_openbsd_arm.go2
-rw-r--r--src/syscall/zerrors_solaris_amd64.go2
-rw-r--r--src/syscall/zerrors_windows.go2
-rw-r--r--src/syscall/zsyscall_darwin_386.go2
-rw-r--r--src/syscall/zsyscall_darwin_amd64.go2
-rw-r--r--src/syscall/zsyscall_darwin_arm.go2
-rw-r--r--src/syscall/zsyscall_darwin_arm64.go2
-rw-r--r--src/syscall/zsyscall_dragonfly_amd64.go2
-rw-r--r--src/syscall/zsyscall_freebsd_386.go2
-rw-r--r--src/syscall/zsyscall_freebsd_amd64.go2
-rw-r--r--src/syscall/zsyscall_freebsd_arm.go2
-rw-r--r--src/syscall/zsyscall_linux_386.go62
-rw-r--r--src/syscall/zsyscall_linux_amd64.go62
-rw-r--r--src/syscall/zsyscall_linux_arm.go62
-rw-r--r--src/syscall/zsyscall_linux_arm64.go62
-rw-r--r--src/syscall/zsyscall_linux_mips.go78
-rw-r--r--src/syscall/zsyscall_linux_mips64.go78
-rw-r--r--src/syscall/zsyscall_linux_mips64le.go78
-rw-r--r--src/syscall/zsyscall_linux_mipsle.go78
-rw-r--r--src/syscall/zsyscall_linux_ppc64.go62
-rw-r--r--src/syscall/zsyscall_linux_ppc64le.go62
-rw-r--r--src/syscall/zsyscall_linux_s390x.go62
-rw-r--r--src/syscall/zsyscall_nacl_386.go2
-rw-r--r--src/syscall/zsyscall_nacl_amd64p32.go2
-rw-r--r--src/syscall/zsyscall_nacl_arm.go2
-rw-r--r--src/syscall/zsyscall_netbsd_386.go2
-rw-r--r--src/syscall/zsyscall_netbsd_amd64.go2
-rw-r--r--src/syscall/zsyscall_netbsd_arm.go2
-rw-r--r--src/syscall/zsyscall_openbsd_386.go2
-rw-r--r--src/syscall/zsyscall_openbsd_amd64.go2
-rw-r--r--src/syscall/zsyscall_openbsd_arm.go2
-rw-r--r--src/syscall/zsyscall_plan9_386.go2
-rw-r--r--src/syscall/zsyscall_plan9_amd64.go2
-rw-r--r--src/syscall/zsyscall_plan9_arm.go2
-rw-r--r--src/syscall/zsyscall_solaris_amd64.go2
-rw-r--r--src/syscall/zsyscall_windows.go2
-rw-r--r--src/syscall/zsysctl_openbsd.go2
-rw-r--r--src/syscall/zsysnum_darwin_386.go2
-rw-r--r--src/syscall/zsysnum_darwin_amd64.go2
-rw-r--r--src/syscall/zsysnum_darwin_arm.go2
-rw-r--r--src/syscall/zsysnum_darwin_arm64.go2
-rw-r--r--src/syscall/zsysnum_dragonfly_amd64.go2
-rw-r--r--src/syscall/zsysnum_freebsd_386.go2
-rw-r--r--src/syscall/zsysnum_freebsd_amd64.go2
-rw-r--r--src/syscall/zsysnum_freebsd_arm.go2
-rw-r--r--src/syscall/zsysnum_linux_386.go2
-rw-r--r--src/syscall/zsysnum_linux_amd64.go2
-rw-r--r--src/syscall/zsysnum_linux_arm.go2
-rw-r--r--src/syscall/zsysnum_linux_arm64.go2
-rw-r--r--src/syscall/zsysnum_linux_mips.go2
-rw-r--r--src/syscall/zsysnum_linux_mips64.go2
-rw-r--r--src/syscall/zsysnum_linux_mips64le.go2
-rw-r--r--src/syscall/zsysnum_linux_mipsle.go2
-rw-r--r--src/syscall/zsysnum_linux_ppc64.go2
-rw-r--r--src/syscall/zsysnum_linux_ppc64le.go2
-rw-r--r--src/syscall/zsysnum_linux_s390x.go2
-rw-r--r--src/syscall/zsysnum_netbsd_386.go2
-rw-r--r--src/syscall/zsysnum_netbsd_amd64.go2
-rw-r--r--src/syscall/zsysnum_netbsd_arm.go2
-rw-r--r--src/syscall/zsysnum_openbsd_386.go2
-rw-r--r--src/syscall/zsysnum_openbsd_amd64.go2
-rw-r--r--src/syscall/zsysnum_openbsd_arm.go2
-rw-r--r--src/syscall/zsysnum_plan9.go2
-rw-r--r--src/syscall/ztypes_linux_386.go1
-rw-r--r--src/syscall/ztypes_linux_amd64.go1
-rw-r--r--src/syscall/ztypes_linux_arm.go1
-rw-r--r--src/syscall/ztypes_linux_arm64.go1
-rw-r--r--src/syscall/ztypes_linux_mips.go1
-rw-r--r--src/syscall/ztypes_linux_mips64.go1
-rw-r--r--src/syscall/ztypes_linux_mips64le.go1
-rw-r--r--src/syscall/ztypes_linux_mipsle.go1
-rw-r--r--src/syscall/ztypes_linux_ppc64.go1
-rw-r--r--src/syscall/ztypes_linux_ppc64le.go1
-rw-r--r--src/syscall/ztypes_linux_s390x.go1
-rw-r--r--src/text/template/exec.go22
-rw-r--r--src/text/template/parse/lex.go2
-rw-r--r--src/text/template/parse/node.go40
-rw-r--r--src/text/template/parse/parse.go4
-rw-r--r--src/time/zoneinfo_abbrs_windows.go9
-rw-r--r--src/unicode/letter.go26
-rw-r--r--src/unicode/letter_test.go12
-rw-r--r--test/fixedbugs/issue18640.go21
-rw-r--r--test/fixedbugs/issue23823.go15
-rw-r--r--test/fixedbugs/issue24651a.go24
-rw-r--r--test/fixedbugs/issue24651b.go24
-rw-r--r--test/fixedbugs/issue24763.go21
-rw-r--r--test/fixedbugs/issue24939.go21
-rw-r--r--test/fixedbugs/issue25727.go21
-rw-r--r--test/fixedbugs/issue25776.go99
-rw-r--r--test/fixedbugs/issue25958.go17
-rw-r--r--test/fixedbugs/issue25966.go24
-rw-r--r--test/fixedbugs/issue25984.dir/p.go15
-rw-r--r--test/fixedbugs/issue25984.dir/q.go11
-rw-r--r--test/fixedbugs/issue25984.go7
-rw-r--r--test/fixedbugs/issue25993.go21
-rw-r--r--test/fixedbugs/issue26043.go32
-rw-r--r--test/fixedbugs/issue26097.go47
-rw-r--r--test/fixedbugs/issue26105.go25
-rw-r--r--test/fixedbugs/issue26120.go23
-rw-r--r--test/strcopy.go29
627 files changed, 25379 insertions, 4394 deletions
diff --git a/.github/SUPPORT.md b/.github/SUPPORT.md
index 9a4d7b2759..23fec84fb6 100644
--- a/.github/SUPPORT.md
+++ b/.github/SUPPORT.md
@@ -9,6 +9,6 @@ For asking questions, see:
* [Gophers Slack](https://gophers.slack.com), use the [invite app](https://invite.slack.golangbridge.org/) for access
-* [Stack Overflow](http://stackoverflow.com/questions/tagged/go) with questions tagged "go"
+* [Stack Overflow](https://stackoverflow.com/questions/tagged/go) with questions tagged "go"
* **IRC** channel #go-nuts on Freenode
diff --git a/api/except.txt b/api/except.txt
index 997df042b6..e104f8e17b 100644
--- a/api/except.txt
+++ b/api/except.txt
@@ -362,24 +362,17 @@ pkg syscall (openbsd-386-cgo), const SYS_KILL = 37
pkg syscall (openbsd-amd64), const SYS_KILL = 37
pkg syscall (openbsd-amd64-cgo), const SYS_KILL = 37
pkg unicode, const Version = "9.0.0"
-pkg text/template/parse, method (*VariableNode) Copy() Node
-pkg text/template/parse, method (*VariableNode) String() string
-pkg text/template/parse, method (VariableNode) Position() Pos
-pkg text/template/parse, method (VariableNode) Type() NodeType
-pkg text/template/parse, type PipeNode struct, Decl []*VariableNode
-pkg text/template/parse, type VariableNode struct
-pkg text/template/parse, type VariableNode struct, Ident []string
-pkg text/template/parse, type VariableNode struct, embedded NodeType
-pkg text/template/parse, type VariableNode struct, embedded Pos
pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr
pkg syscall (windows-386), type CertContext struct, CertInfo uintptr
pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo uintptr
pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo uintptr
+pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983295
pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara uintptr
pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus uintptr
pkg syscall (windows-amd64), type CertContext struct, CertInfo uintptr
pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo uintptr
pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo uintptr
pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo uintptr
+pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983295
diff --git a/api/go1.11.txt b/api/go1.11.txt
new file mode 100644
index 0000000000..d474cf0e8d
--- /dev/null
+++ b/api/go1.11.txt
@@ -0,0 +1,546 @@
+pkg crypto/cipher, func NewGCMWithTagSize(Block, int) (AEAD, error)
+pkg crypto/rsa, method (*PrivateKey) Size() int
+pkg crypto/rsa, method (*PublicKey) Size() int
+pkg crypto/tls, type ConnectionState struct, ExportKeyingMaterial func(string, []uint8, int) ([]uint8, bool)
+pkg database/sql, method (IsolationLevel) String() string
+pkg database/sql, type DBStats struct, Idle int
+pkg database/sql, type DBStats struct, InUse int
+pkg database/sql, type DBStats struct, MaxIdleClosed int64
+pkg database/sql, type DBStats struct, MaxLifetimeClosed int64
+pkg database/sql, type DBStats struct, MaxOpenConnections int
+pkg database/sql, type DBStats struct, WaitCount int64
+pkg database/sql, type DBStats struct, WaitDuration time.Duration
+pkg debug/elf, const ELFOSABI_AROS = 15
+pkg debug/elf, const ELFOSABI_AROS OSABI
+pkg debug/elf, const ELFOSABI_CLOUDABI = 17
+pkg debug/elf, const ELFOSABI_CLOUDABI OSABI
+pkg debug/elf, const ELFOSABI_FENIXOS = 16
+pkg debug/elf, const ELFOSABI_FENIXOS OSABI
+pkg debug/elf, const EM_56800EX = 200
+pkg debug/elf, const EM_56800EX Machine
+pkg debug/elf, const EM_68HC05 = 72
+pkg debug/elf, const EM_68HC05 Machine
+pkg debug/elf, const EM_68HC08 = 71
+pkg debug/elf, const EM_68HC08 Machine
+pkg debug/elf, const EM_68HC11 = 70
+pkg debug/elf, const EM_68HC11 Machine
+pkg debug/elf, const EM_68HC16 = 69
+pkg debug/elf, const EM_68HC16 Machine
+pkg debug/elf, const EM_78KOR = 199
+pkg debug/elf, const EM_78KOR Machine
+pkg debug/elf, const EM_8051 = 165
+pkg debug/elf, const EM_8051 Machine
+pkg debug/elf, const EM_ALTERA_NIOS2 = 113
+pkg debug/elf, const EM_ALTERA_NIOS2 Machine
+pkg debug/elf, const EM_AMDGPU = 224
+pkg debug/elf, const EM_AMDGPU Machine
+pkg debug/elf, const EM_ARCA = 109
+pkg debug/elf, const EM_ARCA Machine
+pkg debug/elf, const EM_ARC_COMPACT = 93
+pkg debug/elf, const EM_ARC_COMPACT Machine
+pkg debug/elf, const EM_ARC_COMPACT2 = 195
+pkg debug/elf, const EM_ARC_COMPACT2 Machine
+pkg debug/elf, const EM_AVR = 83
+pkg debug/elf, const EM_AVR Machine
+pkg debug/elf, const EM_AVR32 = 185
+pkg debug/elf, const EM_AVR32 Machine
+pkg debug/elf, const EM_BA1 = 201
+pkg debug/elf, const EM_BA1 Machine
+pkg debug/elf, const EM_BA2 = 202
+pkg debug/elf, const EM_BA2 Machine
+pkg debug/elf, const EM_BLACKFIN = 106
+pkg debug/elf, const EM_BLACKFIN Machine
+pkg debug/elf, const EM_BPF = 247
+pkg debug/elf, const EM_BPF Machine
+pkg debug/elf, const EM_C166 = 116
+pkg debug/elf, const EM_C166 Machine
+pkg debug/elf, const EM_CDP = 215
+pkg debug/elf, const EM_CDP Machine
+pkg debug/elf, const EM_CE = 119
+pkg debug/elf, const EM_CE Machine
+pkg debug/elf, const EM_CLOUDSHIELD = 192
+pkg debug/elf, const EM_CLOUDSHIELD Machine
+pkg debug/elf, const EM_COGE = 216
+pkg debug/elf, const EM_COGE Machine
+pkg debug/elf, const EM_COOL = 217
+pkg debug/elf, const EM_COOL Machine
+pkg debug/elf, const EM_COREA_1ST = 193
+pkg debug/elf, const EM_COREA_1ST Machine
+pkg debug/elf, const EM_COREA_2ND = 194
+pkg debug/elf, const EM_COREA_2ND Machine
+pkg debug/elf, const EM_CR = 103
+pkg debug/elf, const EM_CR Machine
+pkg debug/elf, const EM_CR16 = 177
+pkg debug/elf, const EM_CR16 Machine
+pkg debug/elf, const EM_CRAYNV2 = 172
+pkg debug/elf, const EM_CRAYNV2 Machine
+pkg debug/elf, const EM_CRIS = 76
+pkg debug/elf, const EM_CRIS Machine
+pkg debug/elf, const EM_CRX = 114
+pkg debug/elf, const EM_CRX Machine
+pkg debug/elf, const EM_CSR_KALIMBA = 219
+pkg debug/elf, const EM_CSR_KALIMBA Machine
+pkg debug/elf, const EM_CUDA = 190
+pkg debug/elf, const EM_CUDA Machine
+pkg debug/elf, const EM_CYPRESS_M8C = 161
+pkg debug/elf, const EM_CYPRESS_M8C Machine
+pkg debug/elf, const EM_D10V = 85
+pkg debug/elf, const EM_D10V Machine
+pkg debug/elf, const EM_D30V = 86
+pkg debug/elf, const EM_D30V Machine
+pkg debug/elf, const EM_DSP24 = 136
+pkg debug/elf, const EM_DSP24 Machine
+pkg debug/elf, const EM_DSPIC30F = 118
+pkg debug/elf, const EM_DSPIC30F Machine
+pkg debug/elf, const EM_DXP = 112
+pkg debug/elf, const EM_DXP Machine
+pkg debug/elf, const EM_ECOG1 = 168
+pkg debug/elf, const EM_ECOG1 Machine
+pkg debug/elf, const EM_ECOG16 = 176
+pkg debug/elf, const EM_ECOG16 Machine
+pkg debug/elf, const EM_ECOG1X = 168
+pkg debug/elf, const EM_ECOG1X Machine
+pkg debug/elf, const EM_ECOG2 = 134
+pkg debug/elf, const EM_ECOG2 Machine
+pkg debug/elf, const EM_ETPU = 178
+pkg debug/elf, const EM_ETPU Machine
+pkg debug/elf, const EM_EXCESS = 111
+pkg debug/elf, const EM_EXCESS Machine
+pkg debug/elf, const EM_F2MC16 = 104
+pkg debug/elf, const EM_F2MC16 Machine
+pkg debug/elf, const EM_FIREPATH = 78
+pkg debug/elf, const EM_FIREPATH Machine
+pkg debug/elf, const EM_FR30 = 84
+pkg debug/elf, const EM_FR30 Machine
+pkg debug/elf, const EM_FT32 = 222
+pkg debug/elf, const EM_FT32 Machine
+pkg debug/elf, const EM_FX66 = 66
+pkg debug/elf, const EM_FX66 Machine
+pkg debug/elf, const EM_HUANY = 81
+pkg debug/elf, const EM_HUANY Machine
+pkg debug/elf, const EM_INTEL205 = 205
+pkg debug/elf, const EM_INTEL205 Machine
+pkg debug/elf, const EM_INTEL206 = 206
+pkg debug/elf, const EM_INTEL206 Machine
+pkg debug/elf, const EM_INTEL207 = 207
+pkg debug/elf, const EM_INTEL207 Machine
+pkg debug/elf, const EM_INTEL208 = 208
+pkg debug/elf, const EM_INTEL208 Machine
+pkg debug/elf, const EM_INTEL209 = 209
+pkg debug/elf, const EM_INTEL209 Machine
+pkg debug/elf, const EM_IP2K = 101
+pkg debug/elf, const EM_IP2K Machine
+pkg debug/elf, const EM_JAVELIN = 77
+pkg debug/elf, const EM_JAVELIN Machine
+pkg debug/elf, const EM_K10M = 181
+pkg debug/elf, const EM_K10M Machine
+pkg debug/elf, const EM_KM32 = 210
+pkg debug/elf, const EM_KM32 Machine
+pkg debug/elf, const EM_KMX16 = 212
+pkg debug/elf, const EM_KMX16 Machine
+pkg debug/elf, const EM_KMX32 = 211
+pkg debug/elf, const EM_KMX32 Machine
+pkg debug/elf, const EM_KMX8 = 213
+pkg debug/elf, const EM_KMX8 Machine
+pkg debug/elf, const EM_KVARC = 214
+pkg debug/elf, const EM_KVARC Machine
+pkg debug/elf, const EM_L10M = 180
+pkg debug/elf, const EM_L10M Machine
+pkg debug/elf, const EM_LANAI = 244
+pkg debug/elf, const EM_LANAI Machine
+pkg debug/elf, const EM_LATTICEMICO32 = 138
+pkg debug/elf, const EM_LATTICEMICO32 Machine
+pkg debug/elf, const EM_M16C = 117
+pkg debug/elf, const EM_M16C Machine
+pkg debug/elf, const EM_M32C = 120
+pkg debug/elf, const EM_M32C Machine
+pkg debug/elf, const EM_M32R = 88
+pkg debug/elf, const EM_M32R Machine
+pkg debug/elf, const EM_MANIK = 171
+pkg debug/elf, const EM_MANIK Machine
+pkg debug/elf, const EM_MAX = 102
+pkg debug/elf, const EM_MAX Machine
+pkg debug/elf, const EM_MAXQ30 = 169
+pkg debug/elf, const EM_MAXQ30 Machine
+pkg debug/elf, const EM_MCHP_PIC = 204
+pkg debug/elf, const EM_MCHP_PIC Machine
+pkg debug/elf, const EM_MCST_ELBRUS = 175
+pkg debug/elf, const EM_MCST_ELBRUS Machine
+pkg debug/elf, const EM_METAG = 174
+pkg debug/elf, const EM_METAG Machine
+pkg debug/elf, const EM_MICROBLAZE = 189
+pkg debug/elf, const EM_MICROBLAZE Machine
+pkg debug/elf, const EM_MMDSP_PLUS = 160
+pkg debug/elf, const EM_MMDSP_PLUS Machine
+pkg debug/elf, const EM_MMIX = 80
+pkg debug/elf, const EM_MMIX Machine
+pkg debug/elf, const EM_MN10200 = 90
+pkg debug/elf, const EM_MN10200 Machine
+pkg debug/elf, const EM_MN10300 = 89
+pkg debug/elf, const EM_MN10300 Machine
+pkg debug/elf, const EM_MOXIE = 223
+pkg debug/elf, const EM_MOXIE Machine
+pkg debug/elf, const EM_MSP430 = 105
+pkg debug/elf, const EM_MSP430 Machine
+pkg debug/elf, const EM_NDS32 = 167
+pkg debug/elf, const EM_NDS32 Machine
+pkg debug/elf, const EM_NORC = 218
+pkg debug/elf, const EM_NORC Machine
+pkg debug/elf, const EM_NS32K = 97
+pkg debug/elf, const EM_NS32K Machine
+pkg debug/elf, const EM_OPEN8 = 196
+pkg debug/elf, const EM_OPEN8 Machine
+pkg debug/elf, const EM_OPENRISC = 92
+pkg debug/elf, const EM_OPENRISC Machine
+pkg debug/elf, const EM_PDP10 = 64
+pkg debug/elf, const EM_PDP10 Machine
+pkg debug/elf, const EM_PDP11 = 65
+pkg debug/elf, const EM_PDP11 Machine
+pkg debug/elf, const EM_PDSP = 63
+pkg debug/elf, const EM_PDSP Machine
+pkg debug/elf, const EM_PJ = 91
+pkg debug/elf, const EM_PJ Machine
+pkg debug/elf, const EM_PRISM = 82
+pkg debug/elf, const EM_PRISM Machine
+pkg debug/elf, const EM_QDSP6 = 164
+pkg debug/elf, const EM_QDSP6 Machine
+pkg debug/elf, const EM_R32C = 162
+pkg debug/elf, const EM_R32C Machine
+pkg debug/elf, const EM_RISCV = 243
+pkg debug/elf, const EM_RISCV Machine
+pkg debug/elf, const EM_RL78 = 197
+pkg debug/elf, const EM_RL78 Machine
+pkg debug/elf, const EM_RS08 = 132
+pkg debug/elf, const EM_RS08 Machine
+pkg debug/elf, const EM_RX = 173
+pkg debug/elf, const EM_RX Machine
+pkg debug/elf, const EM_SCORE7 = 135
+pkg debug/elf, const EM_SCORE7 Machine
+pkg debug/elf, const EM_SEP = 108
+pkg debug/elf, const EM_SEP Machine
+pkg debug/elf, const EM_SE_C17 = 139
+pkg debug/elf, const EM_SE_C17 Machine
+pkg debug/elf, const EM_SE_C33 = 107
+pkg debug/elf, const EM_SE_C33 Machine
+pkg debug/elf, const EM_SHARC = 133
+pkg debug/elf, const EM_SHARC Machine
+pkg debug/elf, const EM_SLE9X = 179
+pkg debug/elf, const EM_SLE9X Machine
+pkg debug/elf, const EM_SNP1K = 99
+pkg debug/elf, const EM_SNP1K Machine
+pkg debug/elf, const EM_ST19 = 74
+pkg debug/elf, const EM_ST19 Machine
+pkg debug/elf, const EM_ST200 = 100
+pkg debug/elf, const EM_ST200 Machine
+pkg debug/elf, const EM_ST7 = 68
+pkg debug/elf, const EM_ST7 Machine
+pkg debug/elf, const EM_ST9PLUS = 67
+pkg debug/elf, const EM_ST9PLUS Machine
+pkg debug/elf, const EM_STM8 = 186
+pkg debug/elf, const EM_STM8 Machine
+pkg debug/elf, const EM_STXP7X = 166
+pkg debug/elf, const EM_STXP7X Machine
+pkg debug/elf, const EM_SVX = 73
+pkg debug/elf, const EM_SVX Machine
+pkg debug/elf, const EM_TILE64 = 187
+pkg debug/elf, const EM_TILE64 Machine
+pkg debug/elf, const EM_TILEGX = 191
+pkg debug/elf, const EM_TILEGX Machine
+pkg debug/elf, const EM_TILEPRO = 188
+pkg debug/elf, const EM_TILEPRO Machine
+pkg debug/elf, const EM_TI_ARP32 = 143
+pkg debug/elf, const EM_TI_ARP32 Machine
+pkg debug/elf, const EM_TI_C2000 = 141
+pkg debug/elf, const EM_TI_C2000 Machine
+pkg debug/elf, const EM_TI_C5500 = 142
+pkg debug/elf, const EM_TI_C5500 Machine
+pkg debug/elf, const EM_TI_C6000 = 140
+pkg debug/elf, const EM_TI_C6000 Machine
+pkg debug/elf, const EM_TI_PRU = 144
+pkg debug/elf, const EM_TI_PRU Machine
+pkg debug/elf, const EM_TMM_GPP = 96
+pkg debug/elf, const EM_TMM_GPP Machine
+pkg debug/elf, const EM_TPC = 98
+pkg debug/elf, const EM_TPC Machine
+pkg debug/elf, const EM_TRIMEDIA = 163
+pkg debug/elf, const EM_TRIMEDIA Machine
+pkg debug/elf, const EM_TSK3000 = 131
+pkg debug/elf, const EM_TSK3000 Machine
+pkg debug/elf, const EM_UNICORE = 110
+pkg debug/elf, const EM_UNICORE Machine
+pkg debug/elf, const EM_V850 = 87
+pkg debug/elf, const EM_V850 Machine
+pkg debug/elf, const EM_VAX = 75
+pkg debug/elf, const EM_VAX Machine
+pkg debug/elf, const EM_VIDEOCORE = 95
+pkg debug/elf, const EM_VIDEOCORE Machine
+pkg debug/elf, const EM_VIDEOCORE3 = 137
+pkg debug/elf, const EM_VIDEOCORE3 Machine
+pkg debug/elf, const EM_VIDEOCORE5 = 198
+pkg debug/elf, const EM_VIDEOCORE5 Machine
+pkg debug/elf, const EM_VISIUM = 221
+pkg debug/elf, const EM_VISIUM Machine
+pkg debug/elf, const EM_XCORE = 203
+pkg debug/elf, const EM_XCORE Machine
+pkg debug/elf, const EM_XGATE = 115
+pkg debug/elf, const EM_XGATE Machine
+pkg debug/elf, const EM_XIMO16 = 170
+pkg debug/elf, const EM_XIMO16 Machine
+pkg debug/elf, const EM_XTENSA = 94
+pkg debug/elf, const EM_XTENSA Machine
+pkg debug/elf, const EM_Z80 = 220
+pkg debug/elf, const EM_Z80 Machine
+pkg debug/elf, const EM_ZSP = 79
+pkg debug/elf, const EM_ZSP Machine
+pkg debug/elf, const R_RISCV_32 = 1
+pkg debug/elf, const R_RISCV_32 R_RISCV
+pkg debug/elf, const R_RISCV_64 = 2
+pkg debug/elf, const R_RISCV_64 R_RISCV
+pkg debug/elf, const R_RISCV_ADD16 = 34
+pkg debug/elf, const R_RISCV_ADD16 R_RISCV
+pkg debug/elf, const R_RISCV_ADD32 = 35
+pkg debug/elf, const R_RISCV_ADD32 R_RISCV
+pkg debug/elf, const R_RISCV_ADD64 = 36
+pkg debug/elf, const R_RISCV_ADD64 R_RISCV
+pkg debug/elf, const R_RISCV_ADD8 = 33
+pkg debug/elf, const R_RISCV_ADD8 R_RISCV
+pkg debug/elf, const R_RISCV_ALIGN = 43
+pkg debug/elf, const R_RISCV_ALIGN R_RISCV
+pkg debug/elf, const R_RISCV_BRANCH = 16
+pkg debug/elf, const R_RISCV_BRANCH R_RISCV
+pkg debug/elf, const R_RISCV_CALL = 18
+pkg debug/elf, const R_RISCV_CALL R_RISCV
+pkg debug/elf, const R_RISCV_CALL_PLT = 19
+pkg debug/elf, const R_RISCV_CALL_PLT R_RISCV
+pkg debug/elf, const R_RISCV_COPY = 4
+pkg debug/elf, const R_RISCV_COPY R_RISCV
+pkg debug/elf, const R_RISCV_GNU_VTENTRY = 42
+pkg debug/elf, const R_RISCV_GNU_VTENTRY R_RISCV
+pkg debug/elf, const R_RISCV_GNU_VTINHERIT = 41
+pkg debug/elf, const R_RISCV_GNU_VTINHERIT R_RISCV
+pkg debug/elf, const R_RISCV_GOT_HI20 = 20
+pkg debug/elf, const R_RISCV_GOT_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_GPREL_I = 47
+pkg debug/elf, const R_RISCV_GPREL_I R_RISCV
+pkg debug/elf, const R_RISCV_GPREL_S = 48
+pkg debug/elf, const R_RISCV_GPREL_S R_RISCV
+pkg debug/elf, const R_RISCV_HI20 = 26
+pkg debug/elf, const R_RISCV_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_JAL = 17
+pkg debug/elf, const R_RISCV_JAL R_RISCV
+pkg debug/elf, const R_RISCV_JUMP_SLOT = 5
+pkg debug/elf, const R_RISCV_JUMP_SLOT R_RISCV
+pkg debug/elf, const R_RISCV_LO12_I = 27
+pkg debug/elf, const R_RISCV_LO12_I R_RISCV
+pkg debug/elf, const R_RISCV_LO12_S = 28
+pkg debug/elf, const R_RISCV_LO12_S R_RISCV
+pkg debug/elf, const R_RISCV_NONE = 0
+pkg debug/elf, const R_RISCV_NONE R_RISCV
+pkg debug/elf, const R_RISCV_PCREL_HI20 = 23
+pkg debug/elf, const R_RISCV_PCREL_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_PCREL_LO12_I = 24
+pkg debug/elf, const R_RISCV_PCREL_LO12_I R_RISCV
+pkg debug/elf, const R_RISCV_PCREL_LO12_S = 25
+pkg debug/elf, const R_RISCV_PCREL_LO12_S R_RISCV
+pkg debug/elf, const R_RISCV_RELATIVE = 3
+pkg debug/elf, const R_RISCV_RELATIVE R_RISCV
+pkg debug/elf, const R_RISCV_RELAX = 51
+pkg debug/elf, const R_RISCV_RELAX R_RISCV
+pkg debug/elf, const R_RISCV_RVC_BRANCH = 44
+pkg debug/elf, const R_RISCV_RVC_BRANCH R_RISCV
+pkg debug/elf, const R_RISCV_RVC_JUMP = 45
+pkg debug/elf, const R_RISCV_RVC_JUMP R_RISCV
+pkg debug/elf, const R_RISCV_RVC_LUI = 46
+pkg debug/elf, const R_RISCV_RVC_LUI R_RISCV
+pkg debug/elf, const R_RISCV_SET16 = 55
+pkg debug/elf, const R_RISCV_SET16 R_RISCV
+pkg debug/elf, const R_RISCV_SET32 = 56
+pkg debug/elf, const R_RISCV_SET32 R_RISCV
+pkg debug/elf, const R_RISCV_SET6 = 53
+pkg debug/elf, const R_RISCV_SET6 R_RISCV
+pkg debug/elf, const R_RISCV_SET8 = 54
+pkg debug/elf, const R_RISCV_SET8 R_RISCV
+pkg debug/elf, const R_RISCV_SUB16 = 38
+pkg debug/elf, const R_RISCV_SUB16 R_RISCV
+pkg debug/elf, const R_RISCV_SUB32 = 39
+pkg debug/elf, const R_RISCV_SUB32 R_RISCV
+pkg debug/elf, const R_RISCV_SUB6 = 52
+pkg debug/elf, const R_RISCV_SUB6 R_RISCV
+pkg debug/elf, const R_RISCV_SUB64 = 40
+pkg debug/elf, const R_RISCV_SUB64 R_RISCV
+pkg debug/elf, const R_RISCV_SUB8 = 37
+pkg debug/elf, const R_RISCV_SUB8 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_DTPMOD32 = 6
+pkg debug/elf, const R_RISCV_TLS_DTPMOD32 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_DTPMOD64 = 7
+pkg debug/elf, const R_RISCV_TLS_DTPMOD64 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_DTPREL32 = 8
+pkg debug/elf, const R_RISCV_TLS_DTPREL32 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_DTPREL64 = 9
+pkg debug/elf, const R_RISCV_TLS_DTPREL64 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_GD_HI20 = 22
+pkg debug/elf, const R_RISCV_TLS_GD_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_GOT_HI20 = 21
+pkg debug/elf, const R_RISCV_TLS_GOT_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_TPREL32 = 10
+pkg debug/elf, const R_RISCV_TLS_TPREL32 R_RISCV
+pkg debug/elf, const R_RISCV_TLS_TPREL64 = 11
+pkg debug/elf, const R_RISCV_TLS_TPREL64 R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_ADD = 32
+pkg debug/elf, const R_RISCV_TPREL_ADD R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_HI20 = 29
+pkg debug/elf, const R_RISCV_TPREL_HI20 R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_I = 49
+pkg debug/elf, const R_RISCV_TPREL_I R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_LO12_I = 30
+pkg debug/elf, const R_RISCV_TPREL_LO12_I R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_LO12_S = 31
+pkg debug/elf, const R_RISCV_TPREL_LO12_S R_RISCV
+pkg debug/elf, const R_RISCV_TPREL_S = 50
+pkg debug/elf, const R_RISCV_TPREL_S R_RISCV
+pkg debug/elf, method (R_RISCV) GoString() string
+pkg debug/elf, method (R_RISCV) String() string
+pkg debug/elf, type R_RISCV int
+pkg debug/macho, const CpuArm64 = 16777228
+pkg debug/macho, const CpuArm64 Cpu
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE = 7
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_ARCHITECTURE ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_BASERELOC = 5
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_BASERELOC ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT = 11
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_BOUND_IMPORT ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR = 14
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_COM_DESCRIPTOR ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_DEBUG = 6
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_DEBUG ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT = 13
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_DELAY_IMPORT ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_EXCEPTION = 3
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_EXCEPTION ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_EXPORT = 0
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_EXPORT ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_GLOBALPTR = 8
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_GLOBALPTR ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_IAT = 12
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_IAT ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_IMPORT = 1
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_IMPORT ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG = 10
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_LOAD_CONFIG ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_RESOURCE = 2
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_RESOURCE ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_SECURITY = 4
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_SECURITY ideal-int
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_TLS = 9
+pkg debug/pe, const IMAGE_DIRECTORY_ENTRY_TLS ideal-int
+pkg debug/pe, const IMAGE_FILE_MACHINE_ARM64 = 43620
+pkg debug/pe, const IMAGE_FILE_MACHINE_ARM64 ideal-int
+pkg go/ast, type CompositeLit struct, Incomplete bool
+pkg go/token, method (*File) AddLineColumnInfo(int, string, int, int)
+pkg go/types, func NewInterfaceType([]*Func, []Type) *Interface
+pkg go/types, method (*Interface) EmbeddedType(int) Type
+pkg go/types, method (*Var) Embedded() bool
+pkg net, method (*ListenConfig) Listen(context.Context, string, string) (Listener, error)
+pkg net, method (*ListenConfig) ListenPacket(context.Context, string, string) (PacketConn, error)
+pkg net, type Dialer struct, Control func(string, string, syscall.RawConn) error
+pkg net, type ListenConfig struct
+pkg net, type ListenConfig struct, Control func(string, string, syscall.RawConn) error
+pkg net/http, const StatusMisdirectedRequest = 421
+pkg net/http, const StatusMisdirectedRequest ideal-int
+pkg net/http/httptrace, type ClientTrace struct, Got1xxResponse func(int, textproto.MIMEHeader) error
+pkg os, const ModeIrregular = 524288
+pkg os, const ModeIrregular FileMode
+pkg os, const ModeType = 2399666176
+pkg os, func UserCacheDir() (string, error)
+pkg os/signal, func Ignored(os.Signal) bool
+pkg regexp/syntax, method (Op) String() string
+pkg runtime/trace, func IsEnabled() bool
+pkg runtime/trace, func Log(context.Context, string, string)
+pkg runtime/trace, func Logf(context.Context, string, string, ...interface{})
+pkg runtime/trace, func NewTask(context.Context, string) (context.Context, *Task)
+pkg runtime/trace, func StartRegion(context.Context, string) *Region
+pkg runtime/trace, func WithRegion(context.Context, string, func())
+pkg runtime/trace, method (*Region) End()
+pkg runtime/trace, method (*Task) End()
+pkg runtime/trace, type Region struct
+pkg runtime/trace, type Task struct
+pkg syscall (netbsd-386), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-386), func Pipe2([]int, int) error
+pkg syscall (netbsd-386-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-386-cgo), func Pipe2([]int, int) error
+pkg syscall (netbsd-amd64), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-amd64), func Pipe2([]int, int) error
+pkg syscall (netbsd-amd64-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-amd64-cgo), func Pipe2([]int, int) error
+pkg syscall (netbsd-arm), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-arm), func Pipe2([]int, int) error
+pkg syscall (netbsd-arm-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (netbsd-arm-cgo), func Pipe2([]int, int) error
+pkg syscall (openbsd-386), const SOCK_CLOEXEC = 32768
+pkg syscall (openbsd-386), const SOCK_CLOEXEC ideal-int
+pkg syscall (openbsd-386), const SOCK_NONBLOCK = 16384
+pkg syscall (openbsd-386), const SOCK_NONBLOCK ideal-int
+pkg syscall (openbsd-386), const SYS_ACCEPT4 = 93
+pkg syscall (openbsd-386), const SYS_ACCEPT4 ideal-int
+pkg syscall (openbsd-386), const SYS_PIPE2 = 101
+pkg syscall (openbsd-386), const SYS_PIPE2 ideal-int
+pkg syscall (openbsd-386), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (openbsd-386), func Pipe2([]int, int) error
+pkg syscall (openbsd-386-cgo), const SOCK_CLOEXEC = 32768
+pkg syscall (openbsd-386-cgo), const SOCK_CLOEXEC ideal-int
+pkg syscall (openbsd-386-cgo), const SOCK_NONBLOCK = 16384
+pkg syscall (openbsd-386-cgo), const SOCK_NONBLOCK ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_ACCEPT4 = 93
+pkg syscall (openbsd-386-cgo), const SYS_ACCEPT4 ideal-int
+pkg syscall (openbsd-386-cgo), const SYS_PIPE2 = 101
+pkg syscall (openbsd-386-cgo), const SYS_PIPE2 ideal-int
+pkg syscall (openbsd-386-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (openbsd-386-cgo), func Pipe2([]int, int) error
+pkg syscall (openbsd-amd64), const SOCK_CLOEXEC = 32768
+pkg syscall (openbsd-amd64), const SOCK_CLOEXEC ideal-int
+pkg syscall (openbsd-amd64), const SOCK_NONBLOCK = 16384
+pkg syscall (openbsd-amd64), const SOCK_NONBLOCK ideal-int
+pkg syscall (openbsd-amd64), const SYS_ACCEPT4 = 93
+pkg syscall (openbsd-amd64), const SYS_ACCEPT4 ideal-int
+pkg syscall (openbsd-amd64), const SYS_PIPE2 = 101
+pkg syscall (openbsd-amd64), const SYS_PIPE2 ideal-int
+pkg syscall (openbsd-amd64), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (openbsd-amd64), func Pipe2([]int, int) error
+pkg syscall (openbsd-amd64-cgo), const SOCK_CLOEXEC = 32768
+pkg syscall (openbsd-amd64-cgo), const SOCK_CLOEXEC ideal-int
+pkg syscall (openbsd-amd64-cgo), const SOCK_NONBLOCK = 16384
+pkg syscall (openbsd-amd64-cgo), const SOCK_NONBLOCK ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_ACCEPT4 = 93
+pkg syscall (openbsd-amd64-cgo), const SYS_ACCEPT4 ideal-int
+pkg syscall (openbsd-amd64-cgo), const SYS_PIPE2 = 101
+pkg syscall (openbsd-amd64-cgo), const SYS_PIPE2 ideal-int
+pkg syscall (openbsd-amd64-cgo), func Accept4(int, int) (int, Sockaddr, error)
+pkg syscall (openbsd-amd64-cgo), func Pipe2([]int, int) error
+pkg syscall (windows-386), const TOKEN_ADJUST_SESSIONID = 256
+pkg syscall (windows-386), const TOKEN_ADJUST_SESSIONID ideal-int
+pkg syscall (windows-386), const TOKEN_ALL_ACCESS = 983551
+pkg syscall (windows-386), type CertChainPolicyPara struct, ExtraPolicyPara Pointer
+pkg syscall (windows-386), type CertChainPolicyStatus struct, ExtraPolicyStatus Pointer
+pkg syscall (windows-386), type CertContext struct, CertInfo *CertInfo
+pkg syscall (windows-386), type CertInfo struct
+pkg syscall (windows-386), type CertRevocationCrlInfo struct
+pkg syscall (windows-386), type CertRevocationInfo struct, CrlInfo *CertRevocationCrlInfo
+pkg syscall (windows-386), type CertRevocationInfo struct, OidSpecificInfo Pointer
+pkg syscall (windows-386), type CertSimpleChain struct, TrustListInfo *CertTrustListInfo
+pkg syscall (windows-386), type CertTrustListInfo struct
+pkg syscall (windows-386), type Pointer *struct
+pkg syscall (windows-amd64), const TOKEN_ADJUST_SESSIONID = 256
+pkg syscall (windows-amd64), const TOKEN_ADJUST_SESSIONID ideal-int
+pkg syscall (windows-amd64), const TOKEN_ALL_ACCESS = 983551
+pkg syscall (windows-amd64), type CertChainPolicyPara struct, ExtraPolicyPara Pointer
+pkg syscall (windows-amd64), type CertChainPolicyStatus struct, ExtraPolicyStatus Pointer
+pkg syscall (windows-amd64), type CertContext struct, CertInfo *CertInfo
+pkg syscall (windows-amd64), type CertInfo struct
+pkg syscall (windows-amd64), type CertRevocationCrlInfo struct
+pkg syscall (windows-amd64), type CertRevocationInfo struct, CrlInfo *CertRevocationCrlInfo
+pkg syscall (windows-amd64), type CertRevocationInfo struct, OidSpecificInfo Pointer
+pkg syscall (windows-amd64), type CertSimpleChain struct, TrustListInfo *CertTrustListInfo
+pkg syscall (windows-amd64), type CertTrustListInfo struct
+pkg syscall (windows-amd64), type Pointer *struct
+pkg syscall, const ImplementsGetwd = true
+pkg text/template/parse, type PipeNode struct, IsAssign bool
diff --git a/doc/code.html b/doc/code.html
index f22e6b4919..4e8c54a1c5 100644
--- a/doc/code.html
+++ b/doc/code.html
@@ -111,6 +111,10 @@ and dependencies in a single workspace.
</p>
<p>
+Note that symbolic links should <b>not</b> be used to link files or directories into your workspace.
+</p>
+
+<p>
Commands and libraries are built from different kinds of source packages.
We will discuss the distinction <a href="#PackageNames">later</a>.
</p>
@@ -236,7 +240,7 @@ package main
import "fmt"
func main() {
- fmt.Printf("Hello, world.\n")
+ fmt.Println("Hello, world.")
}
</pre>
@@ -391,7 +395,7 @@ import (
)
func main() {
- fmt.Printf(stringutil.Reverse("!oG ,olleH"))
+ fmt.Println(stringutil.Reverse("!oG ,olleH"))
}
</pre>
@@ -669,7 +673,7 @@ articles about the Go language and its libraries and tools.
<p>
For real-time help, ask the helpful gophers in <code>#go-nuts</code> on the
-<a href="http://freenode.net/">Freenode</a> IRC server.
+<a href="https://freenode.net/">Freenode</a> IRC server.
</p>
<p>
diff --git a/doc/contribute.html b/doc/contribute.html
index d802bd72a1..388016fac0 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -92,10 +92,10 @@ account to use.
</p>
<p>
-Google accounts can either be Gmail e-mail accounts, G-Suite organization accounts, or
+Google accounts can either be Gmail e-mail accounts, G Suite organization accounts, or
accounts associated with an external e-mail address.
For instance, if you need to use
-an existing corporate e-mail that is not managed through G-Suite, you can create
+an existing corporate e-mail that is not managed through G Suite, you can create
an account associated
<a href="https://accounts.google.com/SignUpWithoutGmail">with your existing
e-mail address</a>.
@@ -168,7 +168,7 @@ completed and update the <code>AUTHORS</code> file.
<h3 id="config_git_auth">Step 2: Configure git authentication</h3>
<p>
-Go development happens on
+The main Go repository is located at
<a href="https://go.googlesource.com">go.googlesource.com</a>,
a Git server hosted by Google.
Authentication on the web server is made through your Google account, but
@@ -190,8 +190,8 @@ This key is paired with one that is generated and stored on the server,
analogous to how SSH keys work.
</li>
<li>
-Copy and run this script locally in your command line terminal to store your
-secret authentication token in a <code>.gitcookies</code> file.
+Copy and run this script locally in your terminal to store your secret
+authentication token in a <code>.gitcookies</code> file.
If you are using a Windows computer and running <code>cmd</code>,
you should instead follow the instructions in the yellow box to run the command;
otherwise run the regular script.
@@ -251,12 +251,13 @@ symbolic link or just copy the executable from $GOPATH/bin to this directory.
<h2 id="before_contributing">Before contributing code</h2>
<p>
-The project welcomes submissions but to make sure things are well
-coordinated we ask that everyone to discuss any significant changes to the
-Go repositories before starting work.
-Best practice is to connect your work to the issue tracker,
-either by <a href="https://golang.org/issue/new">filing a new issue</a>
-or by claiming an <a href="https://golang.org/issues">existing issue</a>.
+The project welcomes code patches, but to make sure things are well
+coordinated you should discuss any significant change before starting
+the work.
+It's recommended that you signal your intention to contribute in the
+issue tracker, either by <a href="https://golang.org/issue/new">filing
+a new issue</a> or by claiming
+an <a href="https://golang.org/issues">existing one</a>.
</p>
<h3>Check the issue tracker</h3>
@@ -309,13 +310,13 @@ When planning work, please note that the Go project follows a <a
href="https://golang.org/wiki/Go-Release-Cycle">six-month development cycle</a>.
The latter half of each cycle is a three-month feature freeze during
which only bug fixes and documentation updates are accepted.
-New contributions can be
-sent during a feature freeze but will not be accepted until the freeze is over.
+New contributions can be sent during a feature freeze, but they will
+not be merged until the freeze is over.
</p>
<p>
-Changes in general other than bug and documentation fixes
-must go through the
+Significant changes to the language, libraries, or tools must go
+through the
<a href="https://golang.org/s/proposal-process">change proposal process</a>
before they can be accepted.
</p>
@@ -337,10 +338,11 @@ GitHub pull requests to Gerrit.
<p>
Open a pull request as you normally would.
-Gopherbot will automatically
-sync the code and post a link to Gerrit.
-When somebody comments on the
-change, it will be posted in the pull request, so you will also get a notification.
+Gopherbot will create a corresponding Gerrit change and post a link to
+it on your GitHub pull request; updates to the pull request will also
+get reflected in the Gerrit change.
+When somebody comments on the change, their comment will be also
+posted in your pull request, so you will get a notification.
</p>
<p>
@@ -384,10 +386,10 @@ This is an overview of the overall process:
<ul>
<li>
-<b>Step 1:</b> Clone the Go source code from GitHub or go.googlesource.com
+<b>Step 1:</b> Clone the Go source code from go.googlesource.com
and make sure it's stable by compiling and testing it once:
<pre>
-$ git clone https://github.com/golang/go # or https://go.googlesource.com/go
+$ git clone https://go.googlesource.com/go
$ cd go/src
$ ./all.bash # compile and test
</pre>
@@ -418,7 +420,7 @@ $ ./all.bash # recompile and test
<li>
<b>Step 4:</b> Send the changes for review to Gerrit using <code>git</code>
-<code>codereview</code> <code>mail</code>(which doesn't use e-mail, despite the name).
+<code>codereview</code> <code>mail</code> (which doesn't use e-mail, despite the name).
<pre>
$ git codereview mail # send changes to Gerrit
</pre>
@@ -545,7 +547,7 @@ ALL TESTS PASSED
<p>
You can use <code>make.bash</code> instead of <code>all.bash</code>
-to just build the compiler and standard packages without running the test suite.
+to just build the compiler and the standard library without running the test suite.
Once the <code>go</code> tool is built, it will be installed as <code>bin/go</code>
under the directory in which you cloned the Go repository, and you can
run it directly from there.
@@ -597,8 +599,9 @@ if you prefer.
</p>
<p>
-If you need to revise your change after the review, edit the files in correct branch,
-add them to the Git staging area, and then amend the commit with
+If you need to revise your change after the review, edit the files in
+the same branch you previously created, add them to the Git staging
+area, and then amend the commit with
<code>git</code> <code>codereview</code> <code>change</code>:
</p>
@@ -639,7 +642,7 @@ The existing implementation has poor numerical properties for
large arguments, so use the McGillicutty algorithm to improve
accuracy above 1e10.
-The algorithm is described at http://wikipedia.org/wiki/McGillicutty_Algorithm
+The algorithm is described at https://wikipedia.org/wiki/McGillicutty_Algorithm
Fixes #159
</pre>
@@ -674,7 +677,7 @@ Don't use HTML, Markdown, or any other markup language.
<p>
Add any relevant information, such as benchmark data if the change
-afects performance.
+affects performance.
The <a href="https://godoc.org/golang.org/x/tools/cmd/benchcmp">benchcmp</a>
tool is conventionally used to format
benchmark data for change descriptions.
@@ -937,7 +940,7 @@ remote: ERROR: does not match your user account.
<p>
you need to configure Git for this repository to use the
e-mail address that you registered with.
-To change the e-mail address for this doesn't happen again, run:
+To change the e-mail address to ensure this doesn't happen again, run:
</p>
<pre>
@@ -984,8 +987,8 @@ followed by <code>run.bash</code>.
<li>
In this section, we'll call the directory into which you cloned the Go repository <code>$GODIR</code>.
-The <code>go</code> tool built by <code>$GODIR/make.bash</code>will be installed
-in <code>$GODIR/bin/go</code>and you
+The <code>go</code> tool built by <code>$GODIR/make.bash</code> will be installed
+in <code>$GODIR/bin/go</code> and you
can invoke it to test your code.
For instance, if you
have modified the compiler and you want to test how it affects the
diff --git a/doc/debugging_with_gdb.html b/doc/debugging_with_gdb.html
index 19d36f7d97..f3b4e37a28 100644
--- a/doc/debugging_with_gdb.html
+++ b/doc/debugging_with_gdb.html
@@ -47,7 +47,7 @@ In short, the instructions below should be taken only as a guide to how
to use GDB when it works, not as a guarantee of success.
Besides this overview you might want to consult the
-<a href="http://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
+<a href="https://sourceware.org/gdb/current/onlinedocs/gdb/">GDB manual</a>.
</p>
<p>
@@ -57,7 +57,7 @@ Besides this overview you might want to consult the
<p>
When you compile and link your Go programs with the <code>gc</code> toolchain
-on Linux, Mac OS X, FreeBSD or NetBSD, the resulting binaries contain DWARFv4
+on Linux, macOS, FreeBSD or NetBSD, the resulting binaries contain DWARFv4
debugging information that recent versions (&ge;7.5) of the GDB debugger can
use to inspect a live process or a core dump.
</p>
diff --git a/doc/diagnostics.html b/doc/diagnostics.html
index 35aae156e8..0a7847744b 100644
--- a/doc/diagnostics.html
+++ b/doc/diagnostics.html
@@ -50,7 +50,7 @@ trace. Use tools in isolation to get more precise info.
Profiling is useful for identifying expensive or frequently called sections
of code. The Go runtime provides <a href="https://golang.org/pkg/runtime/pprof/">
profiling data</a> in the format expected by the
-<a href="https://github.com/google/pprof/blob/master/doc/pprof.md">pprof visualization tool</a>.
+<a href="https://github.com/google/pprof/blob/master/doc/README.md">pprof visualization tool</a>.
The profiling data can be collected during testing
via <code>go</code> <code>test</code> or endpoints made available from the <a href="/pkg/net/http/pprof/">
net/http/pprof</a> package. Users need to collect the profiling data and use pprof tools to filter
@@ -127,7 +127,7 @@ so it is recommended to collect only a single profile at a time.
<p>
The Go tools provide text, graph, and <a href="http://valgrind.org/docs/manual/cl-manual.html">callgrind</a>
visualization of the profile data using
-<code><a href="https://github.com/google/pprof/blob/master/doc/pprof.md">go tool pprof</a></code>.
+<code><a href="https://github.com/google/pprof/blob/master/doc/README.md">go tool pprof</a></code>.
Read <a href="https://blog.golang.org/profiling-go-programs">Profiling Go programs</a>
to see them in action.
</p>
diff --git a/doc/docs.html b/doc/docs.html
index 21a9a63d51..955eb3044e 100644
--- a/doc/docs.html
+++ b/doc/docs.html
@@ -195,7 +195,7 @@ See the <a href="/wiki/Articles">Articles page</a> at the
<img class="gopher" src="/doc/gopher/talks.png"/>
-<h3 id="video_tour_of_go"><a href="http://research.swtch.com/gotour">A Video Tour of Go</a></h3>
+<h3 id="video_tour_of_go"><a href="https://research.swtch.com/gotour">A Video Tour of Go</a></h3>
<p>
Three things that make Go fast, fun, and productive:
interfaces, reflection, and concurrency. Builds a toy web crawler to
diff --git a/doc/editors.html b/doc/editors.html
index 617a100130..6f787864c6 100644
--- a/doc/editors.html
+++ b/doc/editors.html
@@ -9,7 +9,7 @@
This document lists commonly used editor plugins and IDEs from the Go ecosystem
that make Go development more productive and seamless.
A comprehensive list of editor support and IDEs for Go development is available at
- <a href="http://golang.org/wiki/IDEsAndTextEditorPlugins">the wiki</a>.
+ <a href="https://golang.org/wiki/IDEsAndTextEditorPlugins">the wiki</a>.
</p>
<h2 id="options">Options</h2>
diff --git a/doc/gccgo_contribute.html b/doc/gccgo_contribute.html
index 1286fcc2be..6374cd0cbe 100644
--- a/doc/gccgo_contribute.html
+++ b/doc/gccgo_contribute.html
@@ -22,7 +22,7 @@ file HACKING</a> in the gofrontend repository.
You must follow the <a href="/doc/contribute.html#copyright">Go copyright
rules</a> for all changes to the gccgo frontend and the associated
libgo library. Code that is part of GCC rather than gccgo must follow
-the general <a href="http://gcc.gnu.org/contribute.html">GCC
+the general <a href="https://gcc.gnu.org/contribute.html">GCC
contribution rules</a>.
</p>
@@ -30,9 +30,9 @@ contribution rules</a>.
<p>
The master sources for the gccgo frontend may be found at
-<a href="http://go.googlesource.com/gofrontend">http://go.googlesource.com/gofrontend</a>.
+<a href="https://go.googlesource.com/gofrontend">https://go.googlesource.com/gofrontend</a>.
They are mirrored
-at <a href="http://github.com/golang/gofrontend">http://github.com/golang/gofrontend</a>.
+at <a href="https://github.com/golang/gofrontend">https://github.com/golang/gofrontend</a>.
The master sources are not buildable by themselves, but only in
conjunction with GCC (in the future, other compilers may be
supported). Changes made to the gccgo frontend are also applied to
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index d4eac12f11..a974bb3680 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -9,7 +9,7 @@ the Go language. The gccgo compiler is a new frontend
for GCC, the widely used GNU compiler. Although the
frontend itself is under a BSD-style license, gccgo is
normally used as part of GCC and is then covered by
-the <a href="http://www.gnu.org/licenses/gpl.html">GNU General Public
+the <a href="https://www.gnu.org/licenses/gpl.html">GNU General Public
License</a> (the license covers gccgo itself as part of GCC; it
does not cover code generated by gccgo).
</p>
@@ -25,7 +25,7 @@ compiler.
<p>
The simplest way to install gccgo is to install a GCC binary release
built to include Go support. GCC binary releases are available from
-<a href="http://gcc.gnu.org/install/binaries.html">various
+<a href="https://gcc.gnu.org/install/binaries.html">various
websites</a> and are typically included as part of GNU/Linux
distributions. We expect that most people who build these binaries
will include Go support.
@@ -79,7 +79,7 @@ If you cannot use a release, or prefer to build gccgo for
yourself,
the gccgo source code is accessible via Subversion. The
GCC web site
-has <a href="http://gcc.gnu.org/svn.html">instructions for getting the
+has <a href="https://gcc.gnu.org/svn.html">instructions for getting the
GCC source code</a>. The gccgo source code is included. As a
convenience, a stable version of the Go support is available in
a branch of the main GCC code
@@ -101,7 +101,7 @@ gccgo</a>.
<p>
Building gccgo is just like building GCC
with one or two additional options. See
-the <a href="http://gcc.gnu.org/install/">instructions on the gcc web
+the <a href="https://gcc.gnu.org/install/">instructions on the gcc web
site</a>. When you run <code>configure</code>, add the
option <code>--enable-languages=c,c++,go</code> (along with other
languages you may want to build). If you are targeting a 32-bit x86,
@@ -156,7 +156,7 @@ option <code>--with-ld=<var>GOLD_BINARY</var></code>.
<p>
A number of prerequisites are required to build GCC, as
described on
-the <a href="http://gcc.gnu.org/install/prerequisites.html">gcc web
+the <a href="https://gcc.gnu.org/install/prerequisites.html">gcc web
site</a>. It is important to install all the prerequisites before
running the gcc <code>configure</code> script.
The prerequisite libraries can be conveniently downloaded using the
diff --git a/doc/go1.11.html b/doc/go1.11.html
new file mode 100644
index 0000000000..9aef342a43
--- /dev/null
+++ b/doc/go1.11.html
@@ -0,0 +1,346 @@
+<!--{
+ "Title": "Go 1.11 Release Notes",
+ "Path": "/doc/go1.11",
+ "Template": true
+}-->
+
+<!--
+NOTE: In this document and others in this directory, the convention is to
+set fixed-width phrases with non-fixed-width spaces, as in
+<code>hello</code> <code>world</code>.
+Do not send CLs removing the interior tags from such phrases.
+-->
+
+<style>
+ ul li { margin: 0.5em 0; }
+</style>
+
+<h2 id="introduction">DRAFT RELEASE NOTES - Introduction to Go 1.11</h2>
+
+<p>
+ <strong>
+ Go 1.11 is not yet released. These are work-in-progress
+ release notes. Go 1.11 is expected to be released in August 2018.
+ </strong>
+</p>
+
+<p>
+ The latest Go release, version 1.11, arrives six months after <a href="go1.10">Go 1.10</a>.
+ Most of its changes are in the implementation of the toolchain, runtime, and libraries.
+ As always, the release maintains the Go 1 <a href="/doc/go1compat.html">promise of compatibility</a>.
+ We expect almost all Go programs to continue to compile and run as before.
+</p>
+
+<h2 id="language">Changes to the language</h2>
+
+<p>
+ There are no changes to the language specification.
+</p>
+
+<h2 id="ports">Ports</h2>
+
+<p>
+ As <a href="go1.10#ports">announced in the Go 1.10 release notes</a>, Go 1.11 now requires
+ OpenBSD 6.2 or later, macOS 10.10 Yosemite or later, or Windows 7 or later;
+ Support for previous versions of these operating systems has been removed.
+</p>
+
+<p>
+ There are <a href="https://golang.org/issue/25206">known issues</a> with NetBSD on i386 hardware.
+</p>
+
+<p><!-- CL 107935 -->
+ TODO: PPC64LE race detector support
+</p>
+
+<h3 id="package-versioning">Package Versioning (vgo)</h3>
+<p>
+ <strong>
+ NOTE: This is not present in go1.11beta1 but will be available in future
+ betas and subsequent releases.
+ </strong>
+ Go 1.11 adds experimental, integrated support for package versioning.
+</p>
+
+<h3 id="wasm">WebAssembly</h3>
+<p>
+ Go 1.11 adds an experimental port to WebAssembly (<code>js/wasm</code>).
+</p>
+
+<h2 id="library">Core library</h2>
+
+<p>
+ All of the changes to the standard library are minor.
+</p>
+
+<h3 id="minor_library_changes">Minor changes to the library</h3>
+
+<p>
+ As always, there are various minor changes and updates to the library,
+ made with the Go 1 <a href="/doc/go1compat">promise of compatibility</a>
+ in mind.
+</p>
+
+<!-- CL 113315: https://golang.org/cl/113315: cmd/asm: enable AVX512 -->
+<!-- CL 100459: https://golang.org/cl/100459: cmd/compile: reject type switch with guarded declaration and no cases -->
+<!-- CL 106797: https://golang.org/cl/106797: cmd/compile: enable indexed export format by default -->
+<!-- CL 108475: https://golang.org/cl/108475: cmd/compile: add softfloat support to mips64{,le} -->
+<!-- CL 97375: https://golang.org/cl/97375: cmd/compile, cmd/compile/internal/syntax: print relative column info -->
+<!-- CL 110395: https://golang.org/cl/110395: cmd/go, cmd/compile: use Windows response files to avoid arg length limits -->
+<!-- CL 107475: https://golang.org/cl/107475: cmd/internal/obj/arm, runtime: delete old ARM softfloat code -->
+<!-- CL 112436: https://golang.org/cl/112436: cmd/pprof: add readline support similar to upstream -->
+<dl id="all"><dt><a href="/pkg/all/">all</a></dt>
+ <dd>
+ <p><!-- CL 93875 -->
+ TODO: <a href="https://golang.org/cl/93875">https://golang.org/cl/93875</a>: enable c-shared/c-archive support for freebsd/amd64
+ </p>
+
+ <p><!-- CL 94255 -->
+ TODO: <a href="https://golang.org/cl/94255">https://golang.org/cl/94255</a>: drop support for Windows Vista or below (Windows XP)
+ </p>
+
+ <p><!-- CL 115038 -->
+ TODO: <a href="https://golang.org/cl/115038">https://golang.org/cl/115038</a>: remove support for macOS 10.9 and earlier
+ </p>
+
+</dl><!-- all -->
+
+<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
+ <dd>
+ <p><!-- CL 64451 -->
+ TODO: <a href="https://golang.org/cl/64451">https://golang.org/cl/64451</a>: randomly read an extra byte of randomness in some places.
+ </p>
+
+</dl><!-- crypto -->
+
+<dl id="crypto/cipher"><dt><a href="/pkg/crypto/cipher/">crypto/cipher</a></dt>
+ <dd>
+ <p><!-- CL 48510, CL 116435 -->
+ TODO: <a href="https://golang.org/cl/48510">https://golang.org/cl/48510</a>: add NewGCMWithTagSize for custom tag sizes.
+ </p>
+
+</dl><!-- crypto/cipher -->
+
+<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
+ <dd>
+ <p><!-- CL 103876 -->
+ TODO: <a href="https://golang.org/cl/103876">https://golang.org/cl/103876</a>: add PublicKey.Size accessor
+ </p>
+
+</dl><!-- crypto/rsa -->
+
+<dl id="debug/elf"><dt><a href="/pkg/debug/elf/">debug/elf</a></dt>
+ <dd>
+ <p><!-- CL 112115 -->
+ TODO: <a href="https://golang.org/cl/112115">https://golang.org/cl/112115</a>: add machine and OSABI constants
+ </p>
+
+</dl><!-- debug/elf -->
+
+<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
+ <dd>
+ <p><!-- CL 110561 -->
+ TODO: <a href="https://golang.org/cl/110561">https://golang.org/cl/110561</a>: allow Marshaling and Unmarshaling private tag class
+ </p>
+
+</dl><!-- encoding/asn1 -->
+
+<dl id="encoding/base32"><dt><a href="/pkg/encoding/base32/">encoding/base32</a></dt>
+ <dd>
+ <p><!-- CL 112516 -->
+ TODO: <a href="https://golang.org/cl/112516">https://golang.org/cl/112516</a>: handle surplus padding consistently
+ </p>
+
+</dl><!-- encoding/base32 -->
+
+<dl id="encoding/csv"><dt><a href="/pkg/encoding/csv/">encoding/csv</a></dt>
+ <dd>
+ <p><!-- CL 99696 -->
+ TODO: <a href="https://golang.org/cl/99696">https://golang.org/cl/99696</a>: disallow quote for use as Comma
+ </p>
+
+</dl><!-- encoding/csv -->
+
+<dl id="go/build, runtime/internal/sys"><dt><a href="/pkg/go/build, runtime/internal/sys/">go/build, runtime/internal/sys</a></dt>
+ <dd>
+ <p><!-- CL 106256 -->
+ TODO: <a href="https://golang.org/cl/106256">https://golang.org/cl/106256</a>: reserve RISC-V arch names
+ </p>
+
+</dl><!-- go/build, runtime/internal/sys -->
+
+<dl id="image/gif"><dt><a href="/pkg/image/gif/">image/gif</a></dt>
+ <dd>
+ <p><!-- CL 93076 -->
+ TODO: <a href="https://golang.org/cl/93076">https://golang.org/cl/93076</a>: support non-looping animated gifs (LoopCount=-1)
+ </p>
+
+</dl><!-- image/gif -->
+
+<dl id="io/ioutil"><dt><a href="/pkg/io/ioutil/">io/ioutil</a></dt>
+ <dd>
+ <p><!-- CL 105675 -->
+ TODO: <a href="https://golang.org/cl/105675">https://golang.org/cl/105675</a>: change TempFile prefix to a pattern
+ </p>
+
+</dl><!-- io/ioutil -->
+
+<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
+ <dd>
+ <p><!-- CL 74851 -->
+ TODO: <a href="https://golang.org/cl/74851">https://golang.org/cl/74851</a>: speed-up addMulVVW on amd64
+ </p>
+
+</dl><!-- math/big -->
+
+<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
+ <dd>
+ <p><!-- CL 72810 -->
+ TODO: <a href="https://golang.org/cl/72810">https://golang.org/cl/72810</a>: add ListenConfig, Dialer.Control to permit socket opts before listen/dial
+ </p>
+
+ <p><!-- CL 76391 -->
+ TODO: <a href="https://golang.org/cl/76391">https://golang.org/cl/76391</a>: implement (*syscall.RawConn).Read/Write on Windows
+ </p>
+
+ <p><!-- CL 107715 -->
+ TODO: <a href="https://golang.org/cl/107715">https://golang.org/cl/107715</a>: add support for splice(2) in (*TCPConn).ReadFrom on Linux
+ </p>
+
+ <p><!-- CL 108297 -->
+ TODO: <a href="https://golang.org/cl/108297">https://golang.org/cl/108297</a>: calling File leaves the socket in nonblocking mode
+ </p>
+
+</dl><!-- net -->
+
+<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
+ <dd>
+ <p><!-- CL 89275 -->
+ TODO: <a href="https://golang.org/cl/89275">https://golang.org/cl/89275</a>: don&#39;t sniff Content-type in Server when X-Content-Type-Options:nosniff
+ </p>
+
+ <p><!-- CL 93296 -->
+ TODO: <a href="https://golang.org/cl/93296">https://golang.org/cl/93296</a>: add StatusMisdirectedRequest (421)
+ </p>
+
+</dl><!-- net/http -->
+
+<dl id="os"><dt><a href="/pkg/os/">os</a></dt>
+ <dd>
+ <p><!-- CL 78835 -->
+ TODO: <a href="https://golang.org/cl/78835">https://golang.org/cl/78835</a>: add UserCacheDir
+ </p>
+
+ <p><!-- CL 94856 -->
+ TODO: <a href="https://golang.org/cl/94856">https://golang.org/cl/94856</a>: add ModeIrregular flag
+ </p>
+
+ <p><!-- CL 99337 -->
+ TODO: <a href="https://golang.org/cl/99337">https://golang.org/cl/99337</a>: enable symlink creation on Windows 10
+ </p>
+
+ <p><!-- CL 100077 -->
+ TODO: <a href="https://golang.org/cl/100077">https://golang.org/cl/100077</a>: use poller when NewFile is called with a blocking descriptor.
+ </p>
+
+</dl><!-- os -->
+
+<dl id="os/signal"><dt><a href="/pkg/os/signal/">os/signal</a></dt>
+ <dd>
+ <p><!-- CL 108376 -->
+ TODO: <a href="https://golang.org/cl/108376">https://golang.org/cl/108376</a>: add func Ignored(sig Signal) bool
+ </p>
+
+</dl><!-- os/signal -->
+
+<dl id="os/user"><dt><a href="/pkg/os/user/">os/user</a></dt>
+ <dd>
+ <p><!-- CL 92456 -->
+ TODO: <a href="https://golang.org/cl/92456">https://golang.org/cl/92456</a>: add a way to enforce pure Go implementation
+ </p>
+
+</dl><!-- os/user -->
+
+<dl id="runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
+ <dd>
+ <p><!-- CL 85887 -->
+ TODO: <a href="https://golang.org/cl/85887">https://golang.org/cl/85887</a>: use sparse mappings for the heap
+ </p>
+
+ <p><!-- CL 94076 -->
+ TODO: <a href="https://golang.org/cl/94076">https://golang.org/cl/94076</a>: use native CAS and memory barrier on ARMv7
+ </p>
+
+ <p><!-- CL 106156 -->
+ TODO: <a href="https://golang.org/cl/106156">https://golang.org/cl/106156</a>: use fixed TLS offsets on darwin/amd64 and darwin/386
+ </p>
+
+ <p><!-- CL 109255 -->
+ TODO: <a href="https://golang.org/cl/109255">https://golang.org/cl/109255</a>: enable memory sanitizer on arm64
+ </p>
+
+</dl><!-- runtime -->
+
+<dl id="runtime,cmd/ld"><dt><a href="/pkg/runtime,cmd/ld/">runtime,cmd/ld</a></dt>
+ <dd>
+ <p><!-- CL 108679 -->
+ TODO: <a href="https://golang.org/cl/108679">https://golang.org/cl/108679</a>: on darwin, create theads using libc
+ </p>
+
+</dl><!-- runtime,cmd/ld -->
+
+<dl id="runtime/pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
+ <dd>
+ <p><!-- CL 102696 -->
+ TODO: <a href="https://golang.org/cl/102696">https://golang.org/cl/102696</a>: introduce &#34;allocs&#34; profile
+ </p>
+
+</dl><!-- runtime/pprof -->
+
+<dl id="runtime/traceback"><dt><a href="/pkg/runtime/traceback/">runtime/traceback</a></dt>
+ <dd>
+ <p><!-- CL 70993 -->
+ TODO: <a href="https://golang.org/cl/70993">https://golang.org/cl/70993</a>: support tracking goroutine ancestor tracebacks with GODEBUG=&#34;tracebackancestors=N&#34;
+ </p>
+
+</dl><!-- runtime/traceback -->
+
+<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
+ <dd>
+ <p><!-- CL 87095 -->
+ TODO: <a href="https://golang.org/cl/87095">https://golang.org/cl/87095</a>: enable profiling of RWMutex
+ </p>
+
+</dl><!-- sync -->
+
+<dl id="syscall"><dt><a href="/pkg/syscall/">syscall</a></dt>
+ <dd>
+ <p><!-- CL 106275 -->
+ TODO: <a href="https://golang.org/cl/106275">https://golang.org/cl/106275</a>: introduce Pointer type and use it instead of uintptr
+ </p>
+
+</dl><!-- syscall -->
+
+<dl id="text/scanner"><dt><a href="/pkg/text/scanner/">text/scanner</a></dt>
+ <dd>
+ <p><!-- CL 112037 -->
+ TODO: <a href="https://golang.org/cl/112037">https://golang.org/cl/112037</a>: return RawString token rather than String for raw string literals
+ </p>
+
+</dl><!-- text/scanner -->
+
+<dl id="text/template"><dt><a href="/pkg/text/template/">text/template</a></dt>
+ <dd>
+ <p><!-- CL 84480 -->
+ TODO: <a href="https://golang.org/cl/84480">https://golang.org/cl/84480</a>: add variable assignments
+ </p>
+
+</dl><!-- text/template -->
+
+<dl id="time"><dt><a href="/pkg/time/">time</a></dt>
+ <dd>
+ <p><!-- CL 98157 -->
+ TODO: <a href="https://golang.org/cl/98157">https://golang.org/cl/98157</a>: add support for parsing timezones denoted by sign and offset
+ </p>
+
+</dl><!-- time -->
diff --git a/doc/go1.2.html b/doc/go1.2.html
index 5370bbbbd6..1f6051418c 100644
--- a/doc/go1.2.html
+++ b/doc/go1.2.html
@@ -860,13 +860,13 @@ The new build tag <code>netgo</code> (off by default) allows the construction of
The <a href="/pkg/net/"><code>net</code></a> package adds a new field
<code>DualStack</code> to the <a href="/pkg/net/#Dialer"><code>Dialer</code></a>
struct for TCP connection setup using a dual IP stack as described in
-<a href="http://tools.ietf.org/html/rfc6555">RFC 6555</a>.
+<a href="https://tools.ietf.org/html/rfc6555">RFC 6555</a>.
</li>
<li>
The <a href="/pkg/net/http/"><code>net/http</code></a> package will no longer
transmit cookies that are incorrect according to
-<a href="http://tools.ietf.org/html/rfc6265">RFC 6265</a>.
+<a href="https://tools.ietf.org/html/rfc6265">RFC 6265</a>.
It just logs an error and sends nothing.
Also,
the <a href="/pkg/net/http/"><code>net/http</code></a> package's
diff --git a/doc/go1.4.html b/doc/go1.4.html
index ca44d56ceb..c8f7c9c525 100644
--- a/doc/go1.4.html
+++ b/doc/go1.4.html
@@ -420,7 +420,7 @@ to automate the running of tools to generate source code before compilation.
For example, it can be used to run the <a href="/cmd/yacc"><code>yacc</code></a>
compiler-compiler on a <code>.y</code> file to produce the Go source file implementing the grammar,
or to automate the generation of <code>String</code> methods for typed constants using the new
-<a href="http://godoc.org/golang.org/x/tools/cmd/stringer">stringer</a>
+<a href="https://godoc.org/golang.org/x/tools/cmd/stringer">stringer</a>
tool in the <code>golang.org/x/tools</code> subrepository.
</p>
@@ -619,9 +619,9 @@ has been created to serve as the location for new developments to support system
calls on all kernels.
It has a nicer structure, with three packages that each hold the implementation of
system calls for one of
-<a href="http://godoc.org/golang.org/x/sys/unix">Unix</a>,
-<a href="http://godoc.org/golang.org/x/sys/windows">Windows</a> and
-<a href="http://godoc.org/golang.org/x/sys/plan9">Plan 9</a>.
+<a href="https://godoc.org/golang.org/x/sys/unix">Unix</a>,
+<a href="https://godoc.org/golang.org/x/sys/windows">Windows</a> and
+<a href="https://godoc.org/golang.org/x/sys/plan9">Plan 9</a>.
These packages will be curated more generously, accepting all reasonable changes
that reflect kernel interfaces in those operating systems.
See the documentation and the article mentioned above for more information.
@@ -670,7 +670,7 @@ The <a href="/pkg/crypto/"><code>crypto</code></a> package now has a
<li>
The <a href="/pkg/crypto/tls/"><code>crypto/tls</code></a> package
-now supports ALPN as defined in <a href="http://tools.ietf.org/html/rfc7301">RFC 7301</a>.
+now supports ALPN as defined in <a href="https://tools.ietf.org/html/rfc7301">RFC 7301</a>.
</li>
<li>
diff --git a/doc/go1.6.html b/doc/go1.6.html
index 9594736e65..902a82d517 100644
--- a/doc/go1.6.html
+++ b/doc/go1.6.html
@@ -116,7 +116,7 @@ instead of generated from <a href="/cmd/yacc/">yacc</a>.
<p>
The compiler, linker, and <code>go</code> command have a new flag <code>-msan</code>,
analogous to <code>-race</code> and only available on linux/amd64,
-that enables interoperation with the <a href="http://clang.llvm.org/docs/MemorySanitizer.html">Clang MemorySanitizer</a>.
+that enables interoperation with the <a href="https://clang.llvm.org/docs/MemorySanitizer.html">Clang MemorySanitizer</a>.
Such interoperation is useful mainly for testing a program containing suspect C or C++ code.
</p>
diff --git a/doc/go1.7.html b/doc/go1.7.html
index 2b0f01d8fb..db60702776 100644
--- a/doc/go1.7.html
+++ b/doc/go1.7.html
@@ -89,7 +89,7 @@ POWER5 architecture.
</p>
<p>
-The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="http://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
+The OpenBSD port now requires OpenBSD 5.6 or later, for access to the <a href="https://man.openbsd.org/getentropy.2"><i>getentropy</i>(2)</a> system call.
</p>
<h3 id="known_issues">Known Issues</h3>
diff --git a/doc/go_faq.html b/doc/go_faq.html
index cc81e49a9b..e020ce12c1 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -97,14 +97,14 @@ What's the origin of the mascot?</h3>
<p>
The mascot and logo were designed by
-<a href="http://reneefrench.blogspot.com">Renée French</a>, who also designed
+<a href="https://reneefrench.blogspot.com">Renée French</a>, who also designed
<a href="https://9p.io/plan9/glenda.html">Glenda</a>,
the Plan 9 bunny.
The <a href="https://blog.golang.org/gopher">gopher</a>
-is derived from one she used for an <a href="http://wfmu.org/">WFMU</a>
+is derived from one she used for an <a href="https://wfmu.org/">WFMU</a>
T-shirt design some years ago.
The logo and mascot are covered by the
-<a href="http://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
+<a href="https://creativecommons.org/licenses/by/3.0/">Creative Commons Attribution 3.0</a>
license.
</p>
@@ -1396,7 +1396,7 @@ reservation does not deprive other processes of memory.
<p>
To find the amount of actual memory allocated to a Go process, use the Unix
<code>top</code> command and consult the <code>RES</code> (Linux) or
-<code>RSIZE</code> (Mac OS X) columns.
+<code>RSIZE</code> (macOS) columns.
<!-- TODO(adg): find out how this works on Windows -->
</p>
@@ -1929,7 +1929,7 @@ func main() {
<p>
Nowadays, most Go programmers use a tool,
-<a href="http://godoc.org/golang.org/x/tools/cmd/goimports">goimports</a>,
+<a href="https://godoc.org/golang.org/x/tools/cmd/goimports">goimports</a>,
which automatically rewrites a Go source file to have the correct imports,
eliminating the unused imports issue in practice.
This program is easily connected to most editors to run automatically when a Go source file is written.
@@ -1968,7 +1968,7 @@ The slowest depend on libraries for which versions of comparable performance
are not available in Go.
For instance, <a href="https://go.googlesource.com/exp/+/master/shootout/pidigits.go">pidigits.go</a>
depends on a multi-precision math package, and the C
-versions, unlike Go's, use <a href="http://gmplib.org/">GMP</a> (which is
+versions, unlike Go's, use <a href="https://gmplib.org/">GMP</a> (which is
written in optimized assembler).
Benchmarks that depend on regular expressions
(<a href="https://go.googlesource.com/exp/+/master/shootout/regex-dna.go">regex-dna.go</a>,
diff --git a/doc/go_spec.html b/doc/go_spec.html
index f1300c105a..f70ff7a02f 100644
--- a/doc/go_spec.html
+++ b/doc/go_spec.html
@@ -69,7 +69,7 @@ language.
<p>
Source code is Unicode text encoded in
-<a href="http://en.wikipedia.org/wiki/UTF-8">UTF-8</a>. The text is not
+<a href="https://en.wikipedia.org/wiki/UTF-8">UTF-8</a>. The text is not
canonicalized, so a single accented code point is distinct from the
same character constructed from combining an accent and a letter;
those are treated as two code points. For simplicity, this document
@@ -104,7 +104,7 @@ unicode_digit = /* a Unicode code point classified as "Number, decimal digit" *
</pre>
<p>
-In <a href="http://www.unicode.org/versions/Unicode8.0.0/">The Unicode Standard 8.0</a>,
+In <a href="https://www.unicode.org/versions/Unicode8.0.0/">The Unicode Standard 8.0</a>,
Section 4.5 "General Category" defines a set of character categories.
Go treats all characters in any of the Letter categories Lu, Ll, Lt, Lm, or Lo
as Unicode letters, and those in the Number category Nd as Unicode digits.
@@ -793,7 +793,7 @@ rune alias for int32
<p>
The value of an <i>n</i>-bit integer is <i>n</i> bits wide and represented using
-<a href="http://en.wikipedia.org/wiki/Two's_complement">two's complement arithmetic</a>.
+<a href="https://en.wikipedia.org/wiki/Two's_complement">two's complement arithmetic</a>.
</p>
<p>
@@ -3543,7 +3543,7 @@ x = q*y + r and |r| &lt; |y|
<p>
with <code>x / y</code> truncated towards zero
-(<a href="http://en.wikipedia.org/wiki/Modulo_operation">"truncated division"</a>).
+(<a href="https://en.wikipedia.org/wiki/Modulo_operation">"truncated division"</a>).
</p>
<pre>
@@ -6109,7 +6109,7 @@ package and may be relative to a repository of installed packages.
<p>
Implementation restriction: A compiler may restrict ImportPaths to
non-empty strings using only characters belonging to
-<a href="http://www.unicode.org/versions/Unicode6.3.0/">Unicode's</a>
+<a href="https://www.unicode.org/versions/Unicode6.3.0/">Unicode's</a>
L, M, N, P, and S general categories (the Graphic characters without
spaces) and may also exclude the characters
<code>!"#$%&amp;'()*,:;&lt;=&gt;?[\]^`{|}</code>
diff --git a/doc/install-source.html b/doc/install-source.html
index 1928b0ba9b..f6d9473d9b 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -98,7 +98,7 @@ goroutines, such as stacks that grow and shrink on demand.
<p>
The compilers can target the DragonFly BSD, FreeBSD, Linux, NetBSD, OpenBSD,
-OS X (Darwin), Plan 9, Solaris and Windows operating systems.
+macOS (Darwin), Plan 9, Solaris and Windows operating systems.
The full set of supported combinations is listed in the discussion of
<a href="#environment">environment variables</a> below.
</p>
@@ -197,7 +197,7 @@ have a <code>git</code> command before proceeding.)
<p>
If you do not have a working Git installation,
follow the instructions on the
-<a href="http://git-scm.com/downloads">Git downloads</a> page.
+<a href="https://git-scm.com/downloads">Git downloads</a> page.
</p>
<h2 id="ccompiler">(Optional) Install a C compiler</h2>
@@ -388,7 +388,7 @@ You can access the latter commands with
<p>
The usual community resources such as
-<code>#go-nuts</code> on the <a href="http://freenode.net/">Freenode</a> IRC server
+<code>#go-nuts</code> on the <a href="https://freenode.net/">Freenode</a> IRC server
and the
<a href="//groups.google.com/group/golang-nuts">Go Nuts</a>
mailing list have active developers that can help you with problems
@@ -468,7 +468,7 @@ These default to the values of <code>$GOHOSTOS</code> and
<p>
Choices for <code>$GOOS</code> are
-<code>darwin</code> (Mac OS X 10.8 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
+<code>darwin</code> (macOS 10.10 and above and iOS), <code>dragonfly</code>, <code>freebsd</code>,
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
Choices for <code>$GOARCH</code> are
diff --git a/doc/install.html b/doc/install.html
index ee1516ac47..3bb4a15b25 100644
--- a/doc/install.html
+++ b/doc/install.html
@@ -17,7 +17,7 @@
<p>
<a href="/dl/" target="_blank">Official binary
distributions</a> are available for the FreeBSD (release 10-STABLE and above),
-Linux, Mac OS X (10.8 and above), and Windows operating systems and
+Linux, macOS (10.10 and above), and Windows operating systems and
the 32-bit (<code>386</code>) and 64-bit (<code>amd64</code>) x86 processor
architectures.
</p>
@@ -49,7 +49,7 @@ If your OS or architecture is not on the list, you may be able to
<tr><td colspan="3"><hr></td></tr>
<tr><td>FreeBSD 10.3 or later</td> <td>amd64, 386</td> <td>Debian GNU/kFreeBSD not supported</td></tr>
<tr valign='top'><td>Linux 2.6.23 or later with glibc</td> <td>amd64, 386, arm, arm64,<br>s390x, ppc64le</td> <td>CentOS/RHEL 5.x not supported.<br>Install from source for other libc.</td></tr>
-<tr><td>macOS 10.8 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup> for <code>cgo</code> support</td></tr>
+<tr><td>macOS 10.10 or later</td> <td>amd64</td> <td>use the clang or gcc<sup>&#8224;</sup> that comes with Xcode<sup>&#8225;</sup> for <code>cgo</code> support</td></tr>
<tr><td>Windows XP SP2 or later</td> <td>amd64, 386</td> <td>use MinGW gcc<sup>&#8224;</sup>. No need for cygwin or msys.</td></tr>
</table>
@@ -57,7 +57,7 @@ If your OS or architecture is not on the list, you may be able to
<sup>&#8224;</sup>A C compiler is required only if you plan to use
<a href="/cmd/cgo">cgo</a>.<br/>
<sup>&#8225;</sup>You only need to install the command line tools for
-<a href="http://developer.apple.com/Xcode/">Xcode</a>. If you have already
+<a href="https://developer.apple.com/Xcode/">Xcode</a>. If you have already
installed Xcode 4.3+, you can install it from the Components tab of the
Downloads preferences panel.
</p>
@@ -74,7 +74,7 @@ first <a href="#uninstall">remove the existing version</a>.
<div id="tarballInstructions">
-<h3 id="tarball">Linux, Mac OS X, and FreeBSD tarballs</h3>
+<h3 id="tarball">Linux, macOS, and FreeBSD tarballs</h3>
<p>
<a href="/dl/">Download the archive</a>
@@ -114,36 +114,11 @@ or execute them from the profile using a command such as
<code>source $HOME/.profile</code>.
</p>
-<h4 id="tarball_non_standard">Installing to a custom location</h4>
-
-<p>
-The Go binary distributions assume they will be installed in
-<code>/usr/local/go</code> (or <code>c:\Go</code> under Windows),
-but it is possible to install the Go tools to a different location.
-In this case you must set the <code>GOROOT</code> environment variable
-to point to the directory in which it was installed.
-</p>
-
-<p>
-For example, if you installed Go to your home directory you should add
-commands like the following to <code>$HOME/.profile</code>:
-</p>
-
-<pre>
-export GOROOT=$HOME/go1.X
-export PATH=$PATH:$GOROOT/bin
-</pre>
-
-<p>
-<b>Note</b>: <code>GOROOT</code> must be set only when installing to a custom
-location.
-</p>
-
</div><!-- tarballInstructions -->
<div id="darwinPackageInstructions">
-<h3 id="osx">Mac OS X package installer</h3>
+<h3 id="macos"><div id="osx"></div>macOS package installer</h3>
<p>
<a href="/dl/">Download the package file</a>,
@@ -301,7 +276,7 @@ which describes some essential concepts about using the Go tools.
<p>
To remove an existing Go installation from your system delete the
<code>go</code> directory. This is usually <code>/usr/local/go</code>
-under Linux, Mac OS X, and FreeBSD or <code>c:\Go</code>
+under Linux, macOS, and FreeBSD or <code>c:\Go</code>
under Windows.
</p>
@@ -310,7 +285,7 @@ You should also remove the Go <code>bin</code> directory from your
<code>PATH</code> environment variable.
Under Linux and FreeBSD you should edit <code>/etc/profile</code> or
<code>$HOME/.profile</code>.
-If you installed Go with the <a href="#osx">Mac OS X package</a> then you
+If you installed Go with the <a href="#macos">macOS package</a> then you
should remove the <code>/etc/paths.d/go</code> file.
Windows users should read the section about <a href="#windows_env">setting
environment variables under Windows</a>.
diff --git a/doc/root.html b/doc/root.html
index 545b28d2d5..b7422f2128 100644
--- a/doc/root.html
+++ b/doc/root.html
@@ -62,7 +62,7 @@ simple, reliable, and efficient software.
<span class="big">Download Go</span>
<span class="desc">
Binary distributions available for<br>
-Linux, Mac OS X, Windows, and more.
+Linux, macOS, Windows, and more.
</span>
</a>
diff --git a/lib/time/update.bash b/lib/time/update.bash
index 26ad79d52d..629e74fce8 100755
--- a/lib/time/update.bash
+++ b/lib/time/update.bash
@@ -8,8 +8,8 @@
# Consult https://www.iana.org/time-zones for the latest versions.
# Versions to use.
-CODE=2017c
-DATA=2017c
+CODE=2018e
+DATA=2018e
set -e
rm -rf work
diff --git a/lib/time/zoneinfo.zip b/lib/time/zoneinfo.zip
index 0703e08e36..08dca21418 100644
--- a/lib/time/zoneinfo.zip
+++ b/lib/time/zoneinfo.zip
Binary files differ
diff --git a/misc/cgo/test/cgo_test.go b/misc/cgo/test/cgo_test.go
index 4462df0059..4c7f676e0b 100644
--- a/misc/cgo/test/cgo_test.go
+++ b/misc/cgo/test/cgo_test.go
@@ -89,6 +89,7 @@ func Test21897(t *testing.T) { test21897(t) }
func Test22906(t *testing.T) { test22906(t) }
func Test24206(t *testing.T) { test24206(t) }
func Test25143(t *testing.T) { test25143(t) }
+func Test23356(t *testing.T) { test23356(t) }
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
func BenchmarkGoString(b *testing.B) { benchGoString(b) }
diff --git a/misc/cgo/test/issue18146.go b/misc/cgo/test/issue18146.go
index 3c600463f0..6483903fed 100644
--- a/misc/cgo/test/issue18146.go
+++ b/misc/cgo/test/issue18146.go
@@ -22,6 +22,10 @@ import (
)
func test18146(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+
if runtime.GOOS == "darwin" {
t.Skipf("skipping flaky test on %s; see golang.org/issue/18202", runtime.GOOS)
}
@@ -33,10 +37,6 @@ func test18146(t *testing.T) {
attempts := 1000
threads := 4
- if testing.Short() {
- attempts = 100
- }
-
// Restrict the number of attempts based on RLIMIT_NPROC.
// Tediously, RLIMIT_NPROC was left out of the syscall package,
// probably because it is not in POSIX.1, so we define it here.
diff --git a/misc/cgo/test/issue23356.go b/misc/cgo/test/issue23356.go
new file mode 100644
index 0000000000..1c390120c8
--- /dev/null
+++ b/misc/cgo/test/issue23356.go
@@ -0,0 +1,19 @@
+// Copyright 2018 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
+
+// int a(void) { return 5; };
+// int r(void) { return 3; };
+import "C"
+import "testing"
+
+func test23356(t *testing.T) {
+ if got, want := C.a(), C.int(5); got != want {
+ t.Errorf("C.a() == %v, expected %v", got, want)
+ }
+ if got, want := C.r(), C.int(3); got != want {
+ t.Errorf("C.r() == %v, expected %v", got, want)
+ }
+}
diff --git a/misc/cgo/test/issue23555.go b/misc/cgo/test/issue23555.go
new file mode 100644
index 0000000000..5fa44e6355
--- /dev/null
+++ b/misc/cgo/test/issue23555.go
@@ -0,0 +1,11 @@
+// Copyright 2018 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.
+
+// Test that we can have two identical cgo packages in a single binary.
+// No runtime test; just make sure it compiles.
+
+package cgotest
+
+import _ "./issue23555a"
+import _ "./issue23555b"
diff --git a/src/syscall/time_js_wasm.s b/misc/cgo/test/issue23555a/a.go
index f08b17006d..cb6626bb2b 100644
--- a/src/syscall/time_js_wasm.s
+++ b/misc/cgo/test/issue23555a/a.go
@@ -2,10 +2,11 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-#include "textflag.h"
+package issue23555
-TEXT ·startTimer(SB),NOSPLIT,$0
- JMP time·startTimer(SB)
+// #include <stdlib.h>
+import "C"
-TEXT ·stopTimer(SB),NOSPLIT,$0
- JMP time·stopTimer(SB)
+func X() {
+ C.free(C.malloc(10))
+}
diff --git a/misc/cgo/test/issue23555b/a.go b/misc/cgo/test/issue23555b/a.go
new file mode 100644
index 0000000000..cb6626bb2b
--- /dev/null
+++ b/misc/cgo/test/issue23555b/a.go
@@ -0,0 +1,12 @@
+// Copyright 2018 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 issue23555
+
+// #include <stdlib.h>
+import "C"
+
+func X() {
+ C.free(C.malloc(10))
+}
diff --git a/misc/cgo/test/issue23720.go b/misc/cgo/test/issue23720.go
new file mode 100644
index 0000000000..934fff3420
--- /dev/null
+++ b/misc/cgo/test/issue23720.go
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+// Test that we can pass compatible typedefs.
+// No runtime test; just make sure it compiles.
+
+package cgotest
+
+/*
+typedef int *issue23720A;
+
+typedef const int *issue23720B;
+
+void issue23720F(issue23720B a) {}
+*/
+import "C"
+
+func Issue23720F() {
+ var x C.issue23720A
+ C.issue23720F(x)
+}
diff --git a/misc/cgo/test/issue9400/gccgo.go b/misc/cgo/test/issue9400/gccgo.go
index 0ef3a8cacf..a9b62b07a0 100644
--- a/misc/cgo/test/issue9400/gccgo.go
+++ b/misc/cgo/test/issue9400/gccgo.go
@@ -16,6 +16,8 @@ import (
// without writing more assembly code, which we haven't bothered to
// do. So this is not much of a test.
+var Baton int32
+
func RewindAndSetgid() {
atomic.StoreInt32(&Baton, 1)
for atomic.LoadInt32(&Baton) != 0 {
diff --git a/misc/cgo/test/issue9400/stubs.go b/misc/cgo/test/issue9400/stubs.go
index 60193dc411..e431c5a28a 100644
--- a/misc/cgo/test/issue9400/stubs.go
+++ b/misc/cgo/test/issue9400/stubs.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build gc
+
package issue9400
var Baton int32
diff --git a/misc/cgo/test/sigprocmask.c b/misc/cgo/test/sigprocmask.c
index bd99647d2b..e77ba5b08e 100644
--- a/misc/cgo/test/sigprocmask.c
+++ b/misc/cgo/test/sigprocmask.c
@@ -4,10 +4,12 @@
// +build !windows
+#include <errno.h>
#include <signal.h>
#include <stdlib.h>
#include <pthread.h>
#include <stdio.h>
+#include <time.h>
#include <unistd.h>
extern void IntoGoAndBack();
@@ -28,11 +30,22 @@ static void* sigthreadfunc(void* unused) {
}
int RunSigThread() {
+ int tries;
pthread_t thread;
int r;
+ struct timespec ts;
- r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
- if (r != 0)
- return r;
- return pthread_join(thread, NULL);
+ for (tries = 0; tries < 20; tries++) {
+ r = pthread_create(&thread, NULL, &sigthreadfunc, NULL);
+ if (r == 0) {
+ return pthread_join(thread, NULL);
+ }
+ if (r != EAGAIN) {
+ return r;
+ }
+ ts.tv_sec = 0;
+ ts.tv_nsec = (tries + 1) * 1000 * 1000; // Milliseconds.
+ nanosleep(&ts, NULL);
+ }
+ return EAGAIN;
}
diff --git a/misc/cgo/testplugin/src/issue25756/main.go b/misc/cgo/testplugin/src/issue25756/main.go
new file mode 100644
index 0000000000..817daf42f6
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue25756/main.go
@@ -0,0 +1,52 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Run the game of life in C using Go for parallelization.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "plugin"
+)
+
+const MAXDIM = 100
+
+var dim = flag.Int("dim", 16, "board dimensions")
+var gen = flag.Int("gen", 10, "generations")
+
+func main() {
+ flag.Parse()
+
+ var a [MAXDIM * MAXDIM]int32
+ for i := 2; i < *dim; i += 8 {
+ for j := 2; j < *dim-3; j += 8 {
+ for y := 0; y < 3; y++ {
+ a[i**dim+j+y] = 1
+ }
+ }
+ }
+
+ p, err := plugin.Open("life.so")
+ if err != nil {
+ panic(err)
+ }
+ f, err := p.Lookup("Run")
+ if err != nil {
+ panic(err)
+ }
+ f.(func(int, int, int, []int32))(*gen, *dim, *dim, a[:])
+
+ for i := 0; i < *dim; i++ {
+ for j := 0; j < *dim; j++ {
+ if a[i**dim+j] == 0 {
+ fmt.Print(" ")
+ } else {
+ fmt.Print("X")
+ }
+ }
+ fmt.Print("\n")
+ }
+}
diff --git a/misc/cgo/testplugin/src/issue25756/plugin/c-life.c b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c
new file mode 100644
index 0000000000..f853163e2f
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue25756/plugin/c-life.c
@@ -0,0 +1,56 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include <assert.h>
+#include "life.h"
+#include "_cgo_export.h"
+
+const int MYCONST = 0;
+
+// Do the actual manipulation of the life board in C. This could be
+// done easily in Go, we are just using C for demonstration
+// purposes.
+void
+Step(int x, int y, int *a, int *n)
+{
+ struct GoStart_return r;
+
+ // Use Go to start 4 goroutines each of which handles 1/4 of the
+ // board.
+ r = GoStart(0, x, y, 0, x / 2, 0, y / 2, a, n);
+ assert(r.r0 == 0 && r.r1 == 100); // test multiple returns
+ r = GoStart(1, x, y, x / 2, x, 0, y / 2, a, n);
+ assert(r.r0 == 1 && r.r1 == 101); // test multiple returns
+ GoStart(2, x, y, 0, x / 2, y / 2, y, a, n);
+ GoStart(3, x, y, x / 2, x, y / 2, y, a, n);
+ GoWait(0);
+ GoWait(1);
+ GoWait(2);
+ GoWait(3);
+}
+
+// The actual computation. This is called in parallel.
+void
+DoStep(int xdim, int ydim, int xstart, int xend, int ystart, int yend, int *a, int *n)
+{
+ int x, y, c, i, j;
+
+ for(x = xstart; x < xend; x++) {
+ for(y = ystart; y < yend; y++) {
+ c = 0;
+ for(i = -1; i <= 1; i++) {
+ for(j = -1; j <= 1; j++) {
+ if(x+i >= 0 && x+i < xdim &&
+ y+j >= 0 && y+j < ydim &&
+ (i != 0 || j != 0))
+ c += a[(x+i)*xdim + (y+j)] != 0;
+ }
+ }
+ if(c == 3 || (c == 2 && a[x*xdim + y] != 0))
+ n[x*xdim + y] = 1;
+ else
+ n[x*xdim + y] = 0;
+ }
+ }
+}
diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.go b/misc/cgo/testplugin/src/issue25756/plugin/life.go
new file mode 100644
index 0000000000..675a192fc1
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue25756/plugin/life.go
@@ -0,0 +1,39 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+// #include "life.h"
+import "C"
+
+import "unsafe"
+
+func Run(gen, x, y int, a []int32) {
+ n := make([]int32, x*y)
+ for i := 0; i < gen; i++ {
+ C.Step(C.int(x), C.int(y), (*C.int)(unsafe.Pointer(&a[0])), (*C.int)(unsafe.Pointer(&n[0])))
+ copy(a, n)
+ }
+}
+
+// Keep the channels visible from Go.
+var chans [4]chan bool
+
+//export GoStart
+// Double return value is just for testing.
+func GoStart(i, xdim, ydim, xstart, xend, ystart, yend C.int, a *C.int, n *C.int) (int, int) {
+ c := make(chan bool, int(C.MYCONST))
+ go func() {
+ C.DoStep(xdim, ydim, xstart, xend, ystart, yend, a, n)
+ c <- true
+ }()
+ chans[i] = c
+ return int(i), int(i + 100)
+}
+
+//export GoWait
+func GoWait(i C.int) {
+ <-chans[i]
+ chans[i] = nil
+}
diff --git a/misc/cgo/testplugin/src/issue25756/plugin/life.h b/misc/cgo/testplugin/src/issue25756/plugin/life.h
new file mode 100644
index 0000000000..11d2b97226
--- /dev/null
+++ b/misc/cgo/testplugin/src/issue25756/plugin/life.h
@@ -0,0 +1,7 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+extern void Step(int, int, int *, int *);
+extern void DoStep(int, int, int, int, int, int, int *, int *);
+extern const int MYCONST;
diff --git a/misc/cgo/testplugin/test.bash b/misc/cgo/testplugin/test.bash
index df38204a4e..bf8ed3cd19 100755
--- a/misc/cgo/testplugin/test.bash
+++ b/misc/cgo/testplugin/test.bash
@@ -15,7 +15,7 @@ goos=$(go env GOOS)
goarch=$(go env GOARCH)
function cleanup() {
- rm -f plugin*.so unnamed*.so iface*.so issue*
+ rm -f plugin*.so unnamed*.so iface*.so life.so issue*
rm -rf host pkg sub iface
}
trap cleanup EXIT
@@ -90,3 +90,12 @@ GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue22295 src/issue22295.pkg/m
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o issue24351.so src/issue24351/plugin.go
GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue24351 src/issue24351/main.go
./issue24351
+
+# Test for issue 25756
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -buildmode=plugin -o life.so issue25756/plugin
+GOPATH=$(pwd) go build -gcflags "$GO_GCFLAGS" -o issue25756 src/issue25756/main.go
+# Fails intermittently, but 20 runs should cause the failure
+for i in `seq 1 20`;
+do
+ ./issue25756 > /dev/null
+done
diff --git a/misc/cgo/testsanitizers/tsan_test.go b/misc/cgo/testsanitizers/tsan_test.go
index ec4e0033fb..314b5072f3 100644
--- a/misc/cgo/testsanitizers/tsan_test.go
+++ b/misc/cgo/testsanitizers/tsan_test.go
@@ -7,9 +7,13 @@ package sanitizers_test
import (
"strings"
"testing"
+ "runtime"
)
func TestTSAN(t *testing.T) {
+ if runtime.GOARCH == "arm64" {
+ t.Skip("skipping test; see https://golang.org/issue/25682")
+ }
t.Parallel()
requireOvercommit(t)
config := configure("thread")
diff --git a/misc/cgo/testshared/src/trivial/trivial.go b/misc/cgo/testshared/src/trivial/trivial.go
index da29a2cadf..6ade47ce36 100644
--- a/misc/cgo/testshared/src/trivial/trivial.go
+++ b/misc/cgo/testshared/src/trivial/trivial.go
@@ -1,4 +1,9 @@
package main
func main() {
+ // This is enough to make sure that the executable references
+ // a type descriptor, which was the cause of
+ // https://golang.org/issue/25970.
+ c := make(chan int)
+ _ = c
}
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index 151de2e2d1..ecb096509f 100755..100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -16,13 +16,11 @@
},
};
- const now = () => {
- const [sec, nsec] = process.hrtime();
- return sec * 1000 + nsec / 1000000;
- };
global.performance = {
- timeOrigin: Date.now() - now(),
- now: now,
+ now() {
+ const [sec, nsec] = process.hrtime();
+ return sec * 1000 + nsec / 1000000;
+ },
};
const util = require("util");
@@ -33,7 +31,7 @@
let outputBuf = "";
global.fs = {
- constants: {},
+ constants: { O_WRONLY: -1, O_RDWR: -1, O_CREAT: -1, O_TRUNC: -1, O_APPEND: -1, O_EXCL: -1, O_NONBLOCK: -1, O_SYNC: -1 }, // unused
writeSync(fd, buf) {
outputBuf += decoder.decode(buf);
const nl = outputBuf.lastIndexOf("\n");
@@ -43,6 +41,11 @@
}
return buf.length;
},
+ openSync(path, flags, mode) {
+ const err = new Error("not implemented");
+ err.code = "ENOSYS";
+ throw err;
+ },
};
}
@@ -58,6 +61,8 @@
console.warn("exit code:", code);
}
};
+ this._callbackTimeouts = new Map();
+ this._nextCallbackTimeoutID = 1;
const mem = () => {
// The buffer may change when requesting more memory.
@@ -76,21 +81,72 @@
}
const loadValue = (addr) => {
+ const f = mem().getFloat64(addr, true);
+ if (!isNaN(f)) {
+ return f;
+ }
+
const id = mem().getUint32(addr, true);
return this._values[id];
}
const storeValue = (addr, v) => {
- if (v === undefined) {
- mem().setUint32(addr, 0, true);
+ if (typeof v === "number") {
+ if (isNaN(v)) {
+ mem().setUint32(addr + 4, 0x7FF80000, true); // NaN
+ mem().setUint32(addr, 0, true);
+ return;
+ }
+ mem().setFloat64(addr, v, true);
return;
}
- if (v === null) {
- mem().setUint32(addr, 1, true);
+
+ mem().setUint32(addr + 4, 0x7FF80000, true); // NaN
+
+ switch (v) {
+ case undefined:
+ mem().setUint32(addr, 1, true);
+ return;
+ case null:
+ mem().setUint32(addr, 2, true);
+ return;
+ case true:
+ mem().setUint32(addr, 3, true);
+ return;
+ case false:
+ mem().setUint32(addr, 4, true);
+ return;
+ }
+
+ if (typeof v === "string") {
+ let ref = this._stringRefs.get(v);
+ if (ref === undefined) {
+ ref = this._values.length;
+ this._values.push(v);
+ this._stringRefs.set(v, ref);
+ }
+ mem().setUint32(addr, ref, true);
return;
}
- this._values.push(v);
- mem().setUint32(addr, this._values.length - 1, true);
+
+ if (typeof v === "symbol") {
+ let ref = this._symbolRefs.get(v);
+ if (ref === undefined) {
+ ref = this._values.length;
+ this._values.push(v);
+ this._symbolRefs.set(v, ref);
+ }
+ mem().setUint32(addr, ref, true);
+ return;
+ }
+
+ let ref = v[this._refProp];
+ if (ref === undefined) {
+ ref = this._values.length;
+ this._values.push(v);
+ v[this._refProp] = ref;
+ }
+ mem().setUint32(addr, ref, true);
}
const loadSlice = (addr) => {
@@ -104,8 +160,7 @@
const len = getInt64(addr + 8);
const a = new Array(len);
for (let i = 0; i < len; i++) {
- const id = mem().getUint32(array + i * 4, true);
- a[i] = this._values[id];
+ a[i] = loadValue(array + i * 8);
}
return a;
}
@@ -116,10 +171,12 @@
return decoder.decode(new DataView(this._inst.exports.mem.buffer, saddr, len));
}
+ const timeOrigin = Date.now() - performance.now();
this.importObject = {
go: {
// func wasmExit(code int32)
"runtime.wasmExit": (sp) => {
+ this.exited = true;
this.exit(mem().getInt32(sp + 8, true));
},
@@ -133,7 +190,7 @@
// func nanotime() int64
"runtime.nanotime": (sp) => {
- setInt64(sp + 8, (performance.timeOrigin + performance.now()) * 1000000);
+ setInt64(sp + 8, (timeOrigin + performance.now()) * 1000000);
},
// func walltime() (sec int64, nsec int32)
@@ -143,124 +200,117 @@
mem().setInt32(sp + 16, (msec % 1000) * 1000000, true);
},
- // func getRandomData(r []byte)
- "runtime.getRandomData": (sp) => {
- crypto.getRandomValues(loadSlice(sp + 8));
+ // func scheduleCallback(delay int64) int32
+ "runtime.scheduleCallback": (sp) => {
+ const id = this._nextCallbackTimeoutID;
+ this._nextCallbackTimeoutID++;
+ this._callbackTimeouts.set(id, setTimeout(
+ () => { this._resolveCallbackPromise(); },
+ getInt64(sp + 8) + 1, // setTimeout has been seen to fire up to 1 millisecond early
+ ));
+ mem().setInt32(sp + 16, id, true);
},
- // func boolVal(value bool) Value
- "syscall/js.boolVal": (sp) => {
- storeValue(sp + 16, mem().getUint8(sp + 8) !== 0);
+ // func clearScheduledCallback(id int32)
+ "runtime.clearScheduledCallback": (sp) => {
+ const id = mem().getInt32(sp + 8, true);
+ clearTimeout(this._callbackTimeouts.get(id));
+ this._callbackTimeouts.delete(id);
},
- // func intVal(value int) Value
- "syscall/js.intVal": (sp) => {
- storeValue(sp + 16, getInt64(sp + 8));
- },
-
- // func floatVal(value float64) Value
- "syscall/js.floatVal": (sp) => {
- storeValue(sp + 16, mem().getFloat64(sp + 8, true));
+ // func getRandomData(r []byte)
+ "runtime.getRandomData": (sp) => {
+ crypto.getRandomValues(loadSlice(sp + 8));
},
- // func stringVal(value string) Value
+ // func stringVal(value string) ref
"syscall/js.stringVal": (sp) => {
storeValue(sp + 24, loadString(sp + 8));
},
- // func (v Value) Get(key string) Value
- "syscall/js.Value.Get": (sp) => {
+ // func valueGet(v ref, p string) ref
+ "syscall/js.valueGet": (sp) => {
storeValue(sp + 32, Reflect.get(loadValue(sp + 8), loadString(sp + 16)));
},
- // func (v Value) set(key string, value Value)
- "syscall/js.Value.set": (sp) => {
+ // func valueSet(v ref, p string, x ref)
+ "syscall/js.valueSet": (sp) => {
Reflect.set(loadValue(sp + 8), loadString(sp + 16), loadValue(sp + 32));
},
- // func (v Value) Index(i int) Value
- "syscall/js.Value.Index": (sp) => {
+ // func valueIndex(v ref, i int) ref
+ "syscall/js.valueIndex": (sp) => {
storeValue(sp + 24, Reflect.get(loadValue(sp + 8), getInt64(sp + 16)));
},
- // func (v Value) setIndex(i int, value Value)
- "syscall/js.Value.setIndex": (sp) => {
+ // valueSetIndex(v ref, i int, x ref)
+ "syscall/js.valueSetIndex": (sp) => {
Reflect.set(loadValue(sp + 8), getInt64(sp + 16), loadValue(sp + 24));
},
- // func (v Value) call(name string, args []Value) (Value, bool)
- "syscall/js.Value.call": (sp) => {
+ // func valueCall(v ref, m string, args []ref) (ref, bool)
+ "syscall/js.valueCall": (sp) => {
try {
const v = loadValue(sp + 8);
const m = Reflect.get(v, loadString(sp + 16));
const args = loadSliceOfValues(sp + 32);
storeValue(sp + 56, Reflect.apply(m, v, args));
- mem().setUint8(sp + 60, 1);
+ mem().setUint8(sp + 64, 1);
} catch (err) {
storeValue(sp + 56, err);
- mem().setUint8(sp + 60, 0);
+ mem().setUint8(sp + 64, 0);
}
},
- // func (v Value) invoke(args []Value) (Value, bool)
- "syscall/js.Value.invoke": (sp) => {
+ // func valueInvoke(v ref, args []ref) (ref, bool)
+ "syscall/js.valueInvoke": (sp) => {
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
storeValue(sp + 40, Reflect.apply(v, undefined, args));
- mem().setUint8(sp + 44, 1);
+ mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
- mem().setUint8(sp + 44, 0);
+ mem().setUint8(sp + 48, 0);
}
},
- // func (v Value) new(args []Value) (Value, bool)
- "syscall/js.Value.new": (sp) => {
+ // func valueNew(v ref, args []ref) (ref, bool)
+ "syscall/js.valueNew": (sp) => {
try {
const v = loadValue(sp + 8);
const args = loadSliceOfValues(sp + 16);
storeValue(sp + 40, Reflect.construct(v, args));
- mem().setUint8(sp + 44, 1);
+ mem().setUint8(sp + 48, 1);
} catch (err) {
storeValue(sp + 40, err);
- mem().setUint8(sp + 44, 0);
+ mem().setUint8(sp + 48, 0);
}
},
- // func (v Value) Float() float64
- "syscall/js.Value.Float": (sp) => {
- mem().setFloat64(sp + 16, parseFloat(loadValue(sp + 8)), true);
- },
-
- // func (v Value) Int() int
- "syscall/js.Value.Int": (sp) => {
- setInt64(sp + 16, parseInt(loadValue(sp + 8)));
- },
-
- // func (v Value) Bool() bool
- "syscall/js.Value.Bool": (sp) => {
- mem().setUint8(sp + 16, !!loadValue(sp + 8));
- },
-
- // func (v Value) Length() int
- "syscall/js.Value.Length": (sp) => {
+ // func valueLength(v ref) int
+ "syscall/js.valueLength": (sp) => {
setInt64(sp + 16, parseInt(loadValue(sp + 8).length));
},
- // func (v Value) prepareString() (Value, int)
- "syscall/js.Value.prepareString": (sp) => {
+ // valuePrepareString(v ref) (ref, int)
+ "syscall/js.valuePrepareString": (sp) => {
const str = encoder.encode(String(loadValue(sp + 8)));
storeValue(sp + 16, str);
setInt64(sp + 24, str.length);
},
- // func (v Value) loadString(b []byte)
- "syscall/js.Value.loadString": (sp) => {
+ // valueLoadString(v ref, b []byte)
+ "syscall/js.valueLoadString": (sp) => {
const str = loadValue(sp + 8);
loadSlice(sp + 16).set(str);
},
+ // func valueInstanceOf(v ref, t ref) bool
+ "syscall/js.valueInstanceOf": (sp) => {
+ mem().setUint8(sp + 24, loadValue(sp + 8) instanceof loadValue(sp + 16));
+ },
+
"debug": (value) => {
console.log(value);
},
@@ -270,7 +320,25 @@
async run(instance) {
this._inst = instance;
- this._values = [undefined, null, global, this._inst.exports.mem]; // TODO: garbage collection
+ this._values = [ // TODO: garbage collection
+ NaN,
+ undefined,
+ null,
+ true,
+ false,
+ global,
+ this._inst.exports.mem,
+ () => { // resolveCallbackPromise
+ if (this.exited) {
+ throw new Error("bad callback: Go program has already exited");
+ }
+ setTimeout(this._resolveCallbackPromise, 0); // make sure it is asynchronous
+ },
+ ];
+ this._stringRefs = new Map();
+ this._symbolRefs = new Map();
+ this._refProp = Symbol();
+ this.exited = false;
const mem = new DataView(this._inst.exports.mem.buffer)
@@ -304,7 +372,16 @@
offset += 8;
});
- this._inst.exports.run(argc, argv);
+ while (true) {
+ const callbackPromise = new Promise((resolve) => {
+ this._resolveCallbackPromise = resolve;
+ });
+ this._inst.exports.run(argc, argv);
+ if (this.exited) {
+ break;
+ }
+ await callbackPromise;
+ }
}
}
@@ -319,9 +396,16 @@
go.env = process.env;
go.exit = process.exit;
WebAssembly.instantiate(fs.readFileSync(process.argv[2]), go.importObject).then((result) => {
+ process.on("exit", () => { // Node.js exits if no callback is pending
+ if (!go.exited) {
+ console.error("error: all goroutines asleep and no JavaScript callback pending - deadlock!");
+ process.exit(1);
+ }
+ });
return go.run(result.instance);
}).catch((err) => {
console.error(err);
+ go.exited = true;
process.exit(1);
});
}
diff --git a/src/archive/zip/struct.go b/src/archive/zip/struct.go
index c545c5b830..c90151d9d4 100644
--- a/src/archive/zip/struct.go
+++ b/src/archive/zip/struct.go
@@ -81,9 +81,17 @@ const (
// See the zip spec for details.
type FileHeader struct {
// Name is the name of the file.
- // It must be a relative path, not start with a drive letter (e.g. C:),
+ //
+ // It must be a relative path, not start with a drive letter (such as "C:"),
// and must use forward slashes instead of back slashes. A trailing slash
// indicates that this file is a directory and should have no data.
+ //
+ // When reading zip files, the Name field is populated from
+ // the zip file directly and is not validated for correctness.
+ // It is the caller's responsibility to sanitize it as
+ // appropriate, including canonicalizing slash directions,
+ // validating that paths are relative, and preventing path
+ // traversal through filenames ("../../../").
Name string
// Comment is any arbitrary user-defined string shorter than 64KiB.
diff --git a/src/bufio/scan.go b/src/bufio/scan.go
index 40aaa4ab81..cefd261464 100644
--- a/src/bufio/scan.go
+++ b/src/bufio/scan.go
@@ -45,14 +45,19 @@ type Scanner struct {
// input. The arguments are an initial substring of the remaining unprocessed
// data and a flag, atEOF, that reports whether the Reader has no more data
// to give. The return values are the number of bytes to advance the input
-// and the next token to return to the user, plus an error, if any. If the
-// data does not yet hold a complete token, for instance if it has no newline
-// while scanning lines, SplitFunc can return (0, nil, nil) to signal the
-// Scanner to read more data into the slice and try again with a longer slice
-// starting at the same point in the input.
+// and the next token to return to the user, if any, plus an error, if any.
//
-// If the returned error is non-nil, scanning stops and the error
-// is returned to the client.
+// Scanning stops if the function returns an error, in which case some of
+// the input may be discarded.
+//
+// Otherwise, the Scanner advances the input. If the token is not nil,
+// the Scanner returns it to the user. If the token is nil, the
+// Scanner reads more data and continues scanning; if there is no more
+// data--if atEOF was true--the Scanner returns. If the data does not
+// yet hold a complete token, for instance if it has no newline while
+// scanning lines, a SplitFunc can return (0, nil, nil) to signal the
+// Scanner to read more data into the slice and try again with a
+// longer slice starting at the same point in the input.
//
// The function is never called with an empty data slice unless atEOF
// is true. If atEOF is true, however, data may be non-empty and,
diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go
index e7ef928fa2..475d7da5f9 100644
--- a/src/cmd/asm/internal/arch/arm64.go
+++ b/src/cmd/asm/internal/arch/arm64.go
@@ -77,7 +77,8 @@ func IsARM64STLXR(op obj.As) bool {
arm64.ALDADDB, arm64.ALDADDH, arm64.ALDADDW, arm64.ALDADDD,
arm64.ALDANDB, arm64.ALDANDH, arm64.ALDANDW, arm64.ALDANDD,
arm64.ALDEORB, arm64.ALDEORH, arm64.ALDEORW, arm64.ALDEORD,
- arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD:
+ arm64.ALDORB, arm64.ALDORH, arm64.ALDORW, arm64.ALDORD,
+ arm64.ALDADDALD, arm64.ALDADDALW:
return true
}
return false
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index 54be761c54..859f71a26b 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -604,6 +604,8 @@ again:
LDORH R5, (RSP), R7 // e7332578
LDORB R5, (R6), R7 // c7302538
LDORB R5, (RSP), R7 // e7332538
+ LDADDALD R2, (R1), R3 // 2300e2f8
+ LDADDALW R5, (R4), R6 // 8600e5b8
// RET
//
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 8375d94c4b..4bd82ebd12 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -64,6 +64,11 @@ a full argument: to allow -mfoo=bar, use CGO_CFLAGS_ALLOW='-mfoo.*',
not just CGO_CFLAGS_ALLOW='-mfoo'. Similarly named variables control
the allowed CPPFLAGS, CXXFLAGS, FFLAGS, and LDFLAGS.
+Also for security reasons, only a limited set of characters are
+permitted, notably alphanumeric characters and a few symbols, such as
+'.', that will not be interpreted in unexpected ways. Attempts to use
+forbidden characters will get a "malformed #cgo argument" error.
+
When building, the CGO_CFLAGS, CGO_CPPFLAGS, CGO_CXXFLAGS, CGO_FFLAGS and
CGO_LDFLAGS environment variables are added to the flags derived from
these directives. Package-specific flags should be set using the
@@ -223,6 +228,26 @@ C compilers are aware of this calling convention and adjust
the call accordingly, but Go cannot. In Go, you must pass
the pointer to the first element explicitly: C.f(&C.x[0]).
+Calling variadic C functions is not supported. It is possible to
+circumvent this by using a C function wrapper. For example:
+
+ package main
+
+ // #include <stdio.h>
+ // #include <stdlib.h>
+ //
+ // static void myprint(char* s) {
+ // printf("%s\n", s);
+ // }
+ import "C"
+ import "unsafe"
+
+ func main() {
+ cs := C.CString("Hello from stdio")
+ C.myprint(cs)
+ C.free(unsafe.Pointer(cs))
+ }
+
A few special functions convert between Go and C types
by making copies of the data. In pseudo-Go definitions:
diff --git a/src/cmd/cgo/main.go b/src/cmd/cgo/main.go
index ce20948cbe..246898ab77 100644
--- a/src/cmd/cgo/main.go
+++ b/src/cmd/cgo/main.go
@@ -17,6 +17,7 @@ import (
"go/ast"
"go/printer"
"go/token"
+ "io"
"io/ioutil"
"os"
"path/filepath"
@@ -279,6 +280,7 @@ func main() {
// concern is other cgo wrappers for the same functions.
// Use the beginning of the md5 of the input to disambiguate.
h := md5.New()
+ io.WriteString(h, *importPath)
fs := make([]*File, len(goFiles))
for i, input := range goFiles {
if *srcDir != "" {
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index e9b7986565..dbc17d2d56 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -609,14 +609,14 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
// We're trying to write a gcc struct that matches gc's layout.
// Use packed attribute to force no padding in this struct in case
// gcc has different packing requirements.
- fmt.Fprintf(fgcc, "\t%s %v *a = v;\n", ctype, p.packedAttribute())
+ fmt.Fprintf(fgcc, "\t%s %v *_cgo_a = v;\n", ctype, p.packedAttribute())
if n.FuncType.Result != nil {
// Save the stack top for use below.
- fmt.Fprintf(fgcc, "\tchar *stktop = _cgo_topofstack();\n")
+ fmt.Fprintf(fgcc, "\tchar *_cgo_stktop = _cgo_topofstack();\n")
}
tr := n.FuncType.Result
if tr != nil {
- fmt.Fprintf(fgcc, "\t__typeof__(a->r) r;\n")
+ fmt.Fprintf(fgcc, "\t__typeof__(_cgo_a->r) _cgo_r;\n")
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
if n.AddError {
@@ -624,9 +624,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
}
fmt.Fprintf(fgcc, "\t")
if tr != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
if c := tr.C.String(); c[len(c)-1] == '*' {
- fmt.Fprint(fgcc, "(__typeof__(a->r)) ")
+ fmt.Fprint(fgcc, "(__typeof__(_cgo_a->r)) ")
}
}
if n.Kind == "macro" {
@@ -637,7 +637,7 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if i > 0 {
fmt.Fprintf(fgcc, ", ")
}
- fmt.Fprintf(fgcc, "a->p%d", i)
+ fmt.Fprintf(fgcc, "_cgo_a->p%d", i)
}
fmt.Fprintf(fgcc, ");\n")
}
@@ -648,9 +648,9 @@ func (p *Package) writeOutputFunc(fgcc *os.File, n *Name) {
if n.FuncType.Result != nil {
// The cgo call may have caused a stack copy (via a callback).
// Adjust the return value pointer appropriately.
- fmt.Fprintf(fgcc, "\ta = (void*)((char*)a + (_cgo_topofstack() - stktop));\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a = (void*)((char*)_cgo_a + (_cgo_topofstack() - _cgo_stktop));\n")
// Save the return value.
- fmt.Fprintf(fgcc, "\ta->r = r;\n")
+ fmt.Fprintf(fgcc, "\t_cgo_a->r = _cgo_r;\n")
}
if n.AddError {
fmt.Fprintf(fgcc, "\treturn _cgo_errno;\n")
@@ -685,12 +685,12 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
fmt.Fprintf(fgcc, ")\n")
fmt.Fprintf(fgcc, "{\n")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "\t%s r;\n", t.C.String())
+ fmt.Fprintf(fgcc, "\t%s _cgo_r;\n", t.C.String())
}
fmt.Fprintf(fgcc, "\t_cgo_tsan_acquire();\n")
fmt.Fprintf(fgcc, "\t")
if t := n.FuncType.Result; t != nil {
- fmt.Fprintf(fgcc, "r = ")
+ fmt.Fprintf(fgcc, "_cgo_r = ")
// Cast to void* to avoid warnings due to omitted qualifiers.
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
@@ -716,7 +716,7 @@ func (p *Package) writeGccgoOutputFunc(fgcc *os.File, n *Name) {
if c := t.C.String(); c[len(c)-1] == '*' {
fmt.Fprintf(fgcc, "(void*)")
}
- fmt.Fprintf(fgcc, "r;\n")
+ fmt.Fprintf(fgcc, "_cgo_r;\n")
}
fmt.Fprintf(fgcc, "}\n")
fmt.Fprintf(fgcc, "\n")
diff --git a/src/cmd/compile/README.md b/src/cmd/compile/README.md
index c8369c7c8c..b78786e5f2 100644
--- a/src/cmd/compile/README.md
+++ b/src/cmd/compile/README.md
@@ -26,7 +26,7 @@ little to do with uppercase GC, which stands for garbage collection.
* `cmd/compile/internal/syntax` (lexer, parser, syntax tree)
In the first phase of compilation, source code is tokenized (lexical analysis),
-parsed (syntactic analyses), and a syntax tree is constructed for each source
+parsed (syntax analysis), and a syntax tree is constructed for each source
file.
Each syntax tree is an exact representation of the respective source file, with
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
index 4459596e24..c396ba06d1 100644
--- a/src/cmd/compile/internal/arm64/ssa.go
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -553,6 +553,28 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p3.From.Reg = arm64.REGTMP
p3.To.Type = obj.TYPE_BRANCH
gc.Patch(p3, p)
+ case ssa.OpARM64LoweredAtomicAdd64Variant,
+ ssa.OpARM64LoweredAtomicAdd32Variant:
+ // LDADDAL Rarg1, (Rarg0), Rout
+ // ADD Rarg1, Rout
+ op := arm64.ALDADDALD
+ if v.Op == ssa.OpARM64LoweredAtomicAdd32Variant {
+ op = arm64.ALDADDALW
+ }
+ r0 := v.Args[0].Reg()
+ r1 := v.Args[1].Reg()
+ out := v.Reg0()
+ p := s.Prog(op)
+ p.From.Type = obj.TYPE_REG
+ p.From.Reg = r1
+ p.To.Type = obj.TYPE_MEM
+ p.To.Reg = r0
+ p.RegTo2 = out
+ p1 := s.Prog(arm64.AADD)
+ p1.From.Type = obj.TYPE_REG
+ p1.From.Reg = r1
+ p1.To.Type = obj.TYPE_REG
+ p1.To.Reg = out
case ssa.OpARM64LoweredAtomicCas64,
ssa.OpARM64LoweredAtomicCas32:
// LDAXR (Rarg0), Rtmp
@@ -603,25 +625,26 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
gc.Patch(p2, p5)
case ssa.OpARM64LoweredAtomicAnd8,
ssa.OpARM64LoweredAtomicOr8:
- // LDAXRB (Rarg0), Rtmp
- // AND/OR Rarg1, Rtmp
- // STLXRB Rtmp, (Rarg0), Rtmp
+ // LDAXRB (Rarg0), Rout
+ // AND/OR Rarg1, Rout
+ // STLXRB Rout, (Rarg0), Rtmp
// CBNZ Rtmp, -3(PC)
r0 := v.Args[0].Reg()
r1 := v.Args[1].Reg()
+ out := v.Reg0()
p := s.Prog(arm64.ALDAXRB)
p.From.Type = obj.TYPE_MEM
p.From.Reg = r0
p.To.Type = obj.TYPE_REG
- p.To.Reg = arm64.REGTMP
+ p.To.Reg = out
p1 := s.Prog(v.Op.Asm())
p1.From.Type = obj.TYPE_REG
p1.From.Reg = r1
p1.To.Type = obj.TYPE_REG
- p1.To.Reg = arm64.REGTMP
+ p1.To.Reg = out
p2 := s.Prog(arm64.ASTLXRB)
p2.From.Type = obj.TYPE_REG
- p2.From.Reg = arm64.REGTMP
+ p2.From.Reg = out
p2.To.Type = obj.TYPE_MEM
p2.To.Reg = r0
p2.RegTo2 = arm64.REGTMP
diff --git a/src/cmd/compile/internal/gc/bexport.go b/src/cmd/compile/internal/gc/bexport.go
index c2672cb319..0d4997ccfc 100644
--- a/src/cmd/compile/internal/gc/bexport.go
+++ b/src/cmd/compile/internal/gc/bexport.go
@@ -1128,16 +1128,20 @@ func (p *exporter) stmtList(list Nodes) {
}
// TODO inlining produces expressions with ninits. we can't export these yet.
// (from fmt.go:1461ff)
- if opprec[n.Op] < 0 {
- p.stmt(n)
- } else {
- p.expr(n)
- }
+ p.node(n)
}
p.op(OEND)
}
+func (p *exporter) node(n *Node) {
+ if opprec[n.Op] < 0 {
+ p.stmt(n)
+ } else {
+ p.expr(n)
+ }
+}
+
func (p *exporter) exprList(list Nodes) {
if p.trace {
if list.Len() == 0 {
@@ -1552,7 +1556,7 @@ func (p *exporter) exprsOrNil(a, b *Node) {
p.expr(a)
}
if ab&2 != 0 {
- p.expr(b)
+ p.node(b)
}
}
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 8215e4652f..c19f548e18 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -1209,7 +1209,7 @@ func (p *importer) exprsOrNil() (a, b *Node) {
a = p.expr()
}
if ab&2 != 0 {
- b = p.expr()
+ b = p.node()
}
return
}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index 6b416c8a5c..ec8f1093b6 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -141,6 +141,7 @@ var runtimeDecls = [...]struct {
{"uint32tofloat64", funcTag, 109},
{"complex128div", funcTag, 110},
{"racefuncenter", funcTag, 111},
+ {"racefuncenterfp", funcTag, 5},
{"racefuncexit", funcTag, 5},
{"raceread", funcTag, 111},
{"racewrite", funcTag, 111},
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index d459c07cbe..140b7f3b2d 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -183,6 +183,7 @@ func complex128div(num complex128, den complex128) (quo complex128)
// race detection
func racefuncenter(uintptr)
+func racefuncenterfp()
func racefuncexit()
func raceread(uintptr)
func racewrite(uintptr)
diff --git a/src/cmd/compile/internal/gc/const.go b/src/cmd/compile/internal/gc/const.go
index 8d841b94dd..2827543e31 100644
--- a/src/cmd/compile/internal/gc/const.go
+++ b/src/cmd/compile/internal/gc/const.go
@@ -243,15 +243,20 @@ func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
n.Type = t
}
- if n.Type.Etype == TIDEAL {
- n.Left = convlit(n.Left, t)
- n.Right = convlit(n.Right, t)
- n.Type = t
+ if n.Type.IsUntyped() {
+ if t.IsInterface() {
+ n.Left, n.Right = defaultlit2(n.Left, n.Right, true)
+ n.Type = n.Left.Type // same as n.Right.Type per defaultlit2
+ } else {
+ n.Left = convlit(n.Left, t)
+ n.Right = convlit(n.Right, t)
+ n.Type = t
+ }
}
return n
- // target is invalid type for a constant? leave alone.
+ // target is invalid type for a constant? leave alone.
case OLITERAL:
if !okforconst[t.Etype] && n.Type.Etype != TNIL {
return defaultlitreuse(n, nil, reuse)
@@ -294,7 +299,7 @@ func convlit1(n *Node, t *types.Type, explicit bool, reuse canReuseNode) *Node {
return n
}
- // avoided repeated calculations, errors
+ // avoid repeated calculations, errors
if eqtype(n.Type, t) {
return n
}
@@ -1266,7 +1271,6 @@ func idealkind(n *Node) Ctype {
OOR,
OPLUS:
k1 := idealkind(n.Left)
-
k2 := idealkind(n.Right)
if k1 > k2 {
return k1
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index dee315d6f0..0baf7e7441 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -151,22 +151,27 @@ func (v *bottomUpVisitor) visitcode(n *Node, min uint32) uint32 {
// Escape analysis.
-// An escape analysis pass for a set of functions.
-// The analysis assumes that closures and the functions in which they
-// appear are analyzed together, so that the aliasing between their
-// variables can be modeled more precisely.
+// An escape analysis pass for a set of functions. The
+// analysis assumes that closures and the functions in which
+// they appear are analyzed together, so that the aliasing
+// between their variables can be modeled more precisely.
//
-// First escfunc, esc and escassign recurse over the ast of each
-// function to dig out flow(dst,src) edges between any
-// pointer-containing nodes and store them in e.nodeEscState(dst).Flowsrc. For
-// variables assigned to a variable in an outer scope or used as a
-// return value, they store a flow(theSink, src) edge to a fake node
-// 'the Sink'. For variables referenced in closures, an edge
-// flow(closure, &var) is recorded and the flow of a closure itself to
-// an outer scope is tracked the same way as other variables.
+// First escfunc, esc and escassign recurse over the ast of
+// each function to dig out flow(dst,src) edges between any
+// pointer-containing nodes and store those edges in
+// e.nodeEscState(dst).Flowsrc. For values assigned to a
+// variable in an outer scope or used as a return value,
+// they store a flow(theSink, src) edge to a fake node 'the
+// Sink'. For variables referenced in closures, an edge
+// flow(closure, &var) is recorded and the flow of a closure
+// itself to an outer scope is tracked the same way as other
+// variables.
//
-// Then escflood walks the graph starting at theSink and tags all
-// variables of it can reach an & node as escaping and all function
+// Then escflood walks the graph in destination-to-source
+// order, starting at theSink, propagating a computed
+// "escape level", and tags as escaping values it can
+// reach that are either & (address-taken) nodes or new(T),
+// and tags pointer-typed or pointer-containing function
// parameters it can reach as leaking.
//
// If a value's address is taken but the address does not escape,
@@ -185,19 +190,6 @@ const (
EscFuncTagged
)
-// There appear to be some loops in the escape graph, causing
-// arbitrary recursion into deeper and deeper levels.
-// Cut this off safely by making minLevel sticky: once you
-// get that deep, you cannot go down any further but you also
-// cannot go up any further. This is a conservative fix.
-// Making minLevel smaller (more negative) would handle more
-// complex chains of indirections followed by address-of operations,
-// at the cost of repeating the traversal once for each additional
-// allowed level when a loop is encountered. Using -2 suffices to
-// pass all the tests we have written so far, which we assume matches
-// the level of complexity we want the escape analysis code to handle.
-const MinLevel = -2
-
// A Level encodes the reference state and context applied to
// (stack, heap) allocated memory.
//
@@ -205,21 +197,49 @@ const MinLevel = -2
// along a path from a destination (sink, return value) to a source
// (allocation, parameter).
//
-// suffixValue is the maximum-copy-started-suffix-level applied to a sink.
-// For example:
-// sink = x.left.left --> level=2, x is dereferenced twice and does not escape to sink.
-// sink = &Node{x} --> level=-1, x is accessible from sink via one "address of"
-// sink = &Node{&Node{x}} --> level=-2, x is accessible from sink via two "address of"
-// sink = &Node{&Node{x.left}} --> level=-1, but x is NOT accessible from sink because it was indirected and then copied.
-// (The copy operations are sometimes implicit in the source code; in this case,
-// value of x.left was copied into a field of a newly allocated Node)
+// suffixValue is the maximum-copy-started-suffix-level on
+// a flow path from a sink/destination. That is, a value
+// with suffixValue N is guaranteed to be dereferenced at least
+// N deep (chained applications of DOTPTR or IND or INDEX)
+// before the result is assigned to a sink.
+//
+// For example, suppose x is a pointer to T, declared type T struct { left, right *T }
+// sink = x.left.left --> level(x)=2, x is reached via two dereferences (DOTPTR) and does not escape to sink.
+// sink = &T{right:x} --> level(x)=-1, x is accessible from sink via one "address of"
+// sink = &T{right:&T{right:x}} --> level(x)=-2, x is accessible from sink via two "address of"
+//
+// However, in the next example x's level value and suffixValue differ:
+// sink = &T{right:&T{right:x.left}} --> level(x).value=-1, level(x).suffixValue=1
+// The positive suffixValue indicates that x is NOT accessible
+// from sink. Without a separate suffixValue to capture this, x would
+// appear to escape because its "value" would be -1. (The copy
+// operations are sometimes implicit in the source code; in this case,
+// the value of x.left was copied into a field of an newly allocated T).
//
+// Each node's level (value and suffixValue) is the maximum for
+// all flow paths from (any) sink to that node.
+
// There's one of these for each Node, and the integer values
// rarely exceed even what can be stored in 4 bits, never mind 8.
type Level struct {
value, suffixValue int8
}
+// There are loops in the escape graph,
+// causing arbitrary recursion into deeper and deeper
+// levels. Cut this off safely by making minLevel sticky:
+// once you get that deep, you cannot go down any further
+// but you also cannot go up any further. This is a
+// conservative fix. Making minLevel smaller (more negative)
+// would handle more complex chains of indirections followed
+// by address-of operations, at the cost of repeating the
+// traversal once for each additional allowed level when a
+// loop is encountered. Using -2 suffices to pass all the
+// tests we have written so far, which we assume matches the
+// level of complexity we want the escape analysis code to
+// handle.
+const MinLevel = -2
+
func (l Level) int() int {
return int(l.value)
}
@@ -269,6 +289,7 @@ func (l Level) dec() Level {
}
// copy returns the level for a copy of a value with level l.
+// The resulting suffixValue is at least zero, or larger if it was already larger.
func (l Level) copy() Level {
return Level{value: l.value, suffixValue: max8(l.suffixValue, 0)}
}
diff --git a/src/cmd/compile/internal/gc/export.go b/src/cmd/compile/internal/gc/export.go
index cd71db3a14..becc4e1f3b 100644
--- a/src/cmd/compile/internal/gc/export.go
+++ b/src/cmd/compile/internal/gc/export.go
@@ -89,7 +89,7 @@ func dumpexport(bout *bio.Writer) {
}
func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op) *Node {
- n := asNode(s.Def)
+ n := asNode(s.PkgDef())
if n == nil {
// iimport should have created a stub ONONAME
// declaration for all imported symbols. The exception
@@ -100,7 +100,7 @@ func importsym(ipkg *types.Pkg, pos src.XPos, s *types.Sym, op Op) *Node {
}
n = dclname(s)
- s.Def = asTypesNode(n)
+ s.SetPkgDef(asTypesNode(n))
s.Importdef = ipkg
}
if n.Op != ONONAME && n.Op != op {
diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go
index a471a909d6..95bf562e2c 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -303,6 +303,7 @@ var (
racewriterange,
supportPopcnt,
supportSSE41,
+ arm64SupportAtomics,
typedmemclr,
typedmemmove,
Udiv,
diff --git a/src/cmd/compile/internal/gc/iexport.go b/src/cmd/compile/internal/gc/iexport.go
index f6e9b8b061..3abbd15e16 100644
--- a/src/cmd/compile/internal/gc/iexport.go
+++ b/src/cmd/compile/internal/gc/iexport.go
@@ -970,15 +970,19 @@ func (w *exportWriter) linkname(s *types.Sym) {
func (w *exportWriter) stmtList(list Nodes) {
for _, n := range list.Slice() {
- if opprec[n.Op] < 0 {
- w.stmt(n)
- } else {
- w.expr(n)
- }
+ w.node(n)
}
w.op(OEND)
}
+func (w *exportWriter) node(n *Node) {
+ if opprec[n.Op] < 0 {
+ w.stmt(n)
+ } else {
+ w.expr(n)
+ }
+}
+
// Caution: stmt will emit more than one node for statement nodes n that have a non-empty
// n.Ninit and where n cannot have a natural init section (such as in "if", "for", etc.).
func (w *exportWriter) stmt(n *Node) {
@@ -1338,7 +1342,7 @@ func (w *exportWriter) exprsOrNil(a, b *Node) {
w.expr(a)
}
if ab&2 != 0 {
- w.expr(b)
+ w.node(b)
}
}
diff --git a/src/cmd/compile/internal/gc/iimport.go b/src/cmd/compile/internal/gc/iimport.go
index 4d66b4b042..54c5d8dc2f 100644
--- a/src/cmd/compile/internal/gc/iimport.go
+++ b/src/cmd/compile/internal/gc/iimport.go
@@ -46,9 +46,7 @@ func expandDecl(n *Node) {
return
}
- inimport = true
r.doDecl(n)
- inimport = false
}
func expandInline(fn *Node) {
@@ -1060,7 +1058,7 @@ func (r *importReader) exprsOrNil() (a, b *Node) {
a = r.expr()
}
if ab&2 != 0 {
- b = r.expr()
+ b = r.node()
}
return
}
diff --git a/src/cmd/compile/internal/gc/inl.go b/src/cmd/compile/internal/gc/inl.go
index 25452911eb..cb3ddaf2a5 100644
--- a/src/cmd/compile/internal/gc/inl.go
+++ b/src/cmd/compile/internal/gc/inl.go
@@ -132,6 +132,12 @@ func caninl(fn *Node) {
return
}
+ // If marked "go:norace" and -race compilation, don't inline.
+ if flag_race && fn.Func.Pragma&Norace != 0 {
+ reason = "marked go:norace with -race compilation"
+ return
+ }
+
// If marked "go:cgo_unsafe_args", don't inline, since the
// function makes assumptions about its argument frame layout.
if fn.Func.Pragma&CgoUnsafeArgs != 0 {
diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go
index e8b33008b4..9f1ea2ab4b 100644
--- a/src/cmd/compile/internal/gc/main.go
+++ b/src/cmd/compile/internal/gc/main.go
@@ -481,15 +481,13 @@ func Main(archInit func(*Arch)) {
// Phase 1: const, type, and names and types of funcs.
// This will gather all the information about types
// and methods but doesn't depend on any of it.
- // We also defer type alias declarations until phase 2
- // to avoid cycles like #18640.
defercheckwidth()
// Don't use range--typecheck can add closures to xtop.
timings.Start("fe", "typecheck", "top1")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op != ODCL && op != OAS && op != OAS2 && (op != ODCLTYPE || !n.Left.Name.Param.Alias) {
+ if op := n.Op; op != ODCL && op != OAS && op != OAS2 {
xtop[i] = typecheck(n, Etop)
}
}
@@ -501,7 +499,7 @@ func Main(archInit func(*Arch)) {
timings.Start("fe", "typecheck", "top2")
for i := 0; i < len(xtop); i++ {
n := xtop[i]
- if op := n.Op; op == ODCL || op == OAS || op == OAS2 || op == ODCLTYPE && n.Left.Name.Param.Alias {
+ if op := n.Op; op == ODCL || op == OAS || op == OAS2 {
xtop[i] = typecheck(n, Etop)
}
}
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index ec1654b83f..8a42fcefd1 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -19,6 +19,10 @@ import (
"cmd/internal/src"
)
+// parseFiles concurrently parses files into *syntax.File structures.
+// Each declaration in every *syntax.File is converted to a syntax tree
+// and its root represented by *Node is appended to xtop.
+// Returns the total count of parsed lines.
func parseFiles(filenames []string) uint {
var noders []*noder
// Limit the number of simultaneously open files.
diff --git a/src/cmd/compile/internal/gc/racewalk.go b/src/cmd/compile/internal/gc/racewalk.go
index 8ae080ab40..df0e5f4059 100644
--- a/src/cmd/compile/internal/gc/racewalk.go
+++ b/src/cmd/compile/internal/gc/racewalk.go
@@ -7,6 +7,7 @@ package gc
import (
"cmd/compile/internal/types"
"cmd/internal/src"
+ "cmd/internal/sys"
)
// The racewalk pass is currently handled in two parts.
@@ -58,17 +59,23 @@ func instrument(fn *Node) {
lno := lineno
lineno = src.NoXPos
- // nodpc is the PC of the caller as extracted by
- // getcallerpc. We use -widthptr(FP) for x86.
- // BUG: this will not work on arm.
- nodpc := nodfp.copy()
- nodpc.Type = types.Types[TUINTPTR]
- nodpc.Xoffset = int64(-Widthptr)
- fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
-
- fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
- fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
+ if thearch.LinkArch.Arch == sys.ArchPPC64LE {
+ fn.Func.Enter.Prepend(mkcall("racefuncenterfp", nil, nil))
+ fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
+ } else {
+ // nodpc is the PC of the caller as extracted by
+ // getcallerpc. We use -widthptr(FP) for x86.
+ // BUG: This only works for amd64. This will not
+ // work on arm or others that might support
+ // race in the future.
+ nodpc := nodfp.copy()
+ nodpc.Type = types.Types[TUINTPTR]
+ nodpc.Xoffset = int64(-Widthptr)
+ fn.Func.Dcl = append(fn.Func.Dcl, nodpc)
+ fn.Func.Enter.Prepend(mkcall("racefuncenter", nil, nil, nodpc))
+ fn.Func.Exit.Append(mkcall("racefuncexit", nil, nil))
+ }
lineno = lno
}
}
diff --git a/src/cmd/compile/internal/gc/select.go b/src/cmd/compile/internal/gc/select.go
index eb37e32bf1..4445edbe92 100644
--- a/src/cmd/compile/internal/gc/select.go
+++ b/src/cmd/compile/internal/gc/select.go
@@ -33,7 +33,15 @@ func typecheckselect(sel *Node) {
ncase.List.Set(nil)
switch n.Op {
default:
- yyerrorl(n.Pos, "select case must be receive, send or assign recv")
+ pos := n.Pos
+ if n.Op == ONAME {
+ // We don't have the right position for ONAME nodes (see #15459 and
+ // others). Using ncase.Pos for now as it will provide the correct
+ // line number (assuming the expression follows the "case" keyword
+ // on the same line). This matches the approach before 1.10.
+ pos = ncase.Pos
+ }
+ yyerrorl(pos, "select case must be receive, send or assign recv")
// convert x = <-c into OSELRECV(x, <-c).
// remove implicit conversions; the eventual assignment
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index a64d212233..ff2b93d3d4 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -78,6 +78,7 @@ func initssaconfig() {
racewriterange = sysfunc("racewriterange")
supportPopcnt = sysfunc("support_popcnt")
supportSSE41 = sysfunc("support_sse41")
+ arm64SupportAtomics = sysfunc("arm64_support_atomics")
typedmemclr = sysfunc("typedmemclr")
typedmemmove = sysfunc("typedmemmove")
Udiv = sysfunc("udiv")
@@ -2169,8 +2170,9 @@ func (s *state) expr(n *Node) *ssa.Value {
p := s.addr(n, false)
return s.load(n.Left.Type.Elem(), p)
case n.Left.Type.IsArray():
- if bound := n.Left.Type.NumElem(); bound <= 1 {
+ if canSSAType(n.Left.Type) {
// SSA can handle arrays of length at most 1.
+ bound := n.Left.Type.NumElem()
a := s.expr(n.Left)
i := s.expr(n.Right)
if bound == 0 {
@@ -2935,14 +2937,56 @@ func init() {
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[TUINT32], v)
},
- sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64)
+ sys.AMD64, sys.S390X, sys.MIPS, sys.MIPS64, sys.PPC64)
addF("runtime/internal/atomic", "Xadd64",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
v := s.newValue3(ssa.OpAtomicAdd64, types.NewTuple(types.Types[TUINT64], types.TypeMem), args[0], args[1], s.mem())
s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v)
return s.newValue1(ssa.OpSelect0, types.Types[TUINT64], v)
},
- sys.AMD64, sys.ARM64, sys.S390X, sys.MIPS64, sys.PPC64)
+ sys.AMD64, sys.S390X, sys.MIPS64, sys.PPC64)
+
+ makeXaddARM64 := func(op0 ssa.Op, op1 ssa.Op, ty types.EType) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
+ // Target Atomic feature is identified by dynamic detection
+ addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), arm64SupportAtomics, s.sb)
+ v := s.load(types.Types[TBOOL], addr)
+ b := s.endBlock()
+ b.Kind = ssa.BlockIf
+ b.SetControl(v)
+ bTrue := s.f.NewBlock(ssa.BlockPlain)
+ bFalse := s.f.NewBlock(ssa.BlockPlain)
+ bEnd := s.f.NewBlock(ssa.BlockPlain)
+ b.AddEdgeTo(bTrue)
+ b.AddEdgeTo(bFalse)
+ b.Likely = ssa.BranchUnlikely // most machines don't have Atomics nowadays
+
+ // We have atomic instructions - use it directly.
+ s.startBlock(bTrue)
+ v0 := s.newValue3(op1, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v0)
+ s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v0)
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Use original instruction sequence.
+ s.startBlock(bFalse)
+ v1 := s.newValue3(op0, types.NewTuple(types.Types[ty], types.TypeMem), args[0], args[1], s.mem())
+ s.vars[&memVar] = s.newValue1(ssa.OpSelect1, types.TypeMem, v1)
+ s.vars[n] = s.newValue1(ssa.OpSelect0, types.Types[ty], v1)
+ s.endBlock().AddEdgeTo(bEnd)
+
+ // Merge results.
+ s.startBlock(bEnd)
+ return s.variable(n, types.Types[ty])
+ }
+ }
+
+ addF("runtime/internal/atomic", "Xadd",
+ makeXaddARM64(ssa.OpAtomicAdd32, ssa.OpAtomicAdd32Variant, TUINT32),
+ sys.ARM64)
+ addF("runtime/internal/atomic", "Xadd64",
+ makeXaddARM64(ssa.OpAtomicAdd64, ssa.OpAtomicAdd64Variant, TUINT64),
+ sys.ARM64)
addF("runtime/internal/atomic", "Cas",
func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
@@ -4985,7 +5029,7 @@ func genssa(f *ssa.Func, pp *Progs) {
}
buf.WriteString("</dl>")
buf.WriteString("</code>")
- f.HTMLWriter.WriteColumn("genssa", "ssa-prog", buf.String())
+ f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
// pp.Text.Ctxt.LineHist.PrintFilenameOnly = saved
}
}
diff --git a/src/cmd/compile/internal/gc/swt.go b/src/cmd/compile/internal/gc/swt.go
index 433d38544e..b668409a88 100644
--- a/src/cmd/compile/internal/gc/swt.go
+++ b/src/cmd/compile/internal/gc/swt.go
@@ -241,6 +241,11 @@ func walkswitch(sw *Node) {
// search using if..goto, although binary search
// is used with long runs of constants.
func (s *exprSwitch) walk(sw *Node) {
+ // Guard against double walk, see #25776.
+ if sw.List.Len() == 0 && sw.Nbody.Len() > 0 {
+ Fatalf("second walk of switch")
+ }
+
casebody(sw, nil)
cond := sw.Left
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 483be32d6e..1b68e057fc 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -37,7 +37,12 @@ func resolve(n *Node) *Node {
}
if n.Sym.Pkg != localpkg {
+ if inimport {
+ Fatalf("recursive inimport")
+ }
+ inimport = true
expandDecl(n)
+ inimport = false
return n
}
@@ -110,19 +115,35 @@ func typekind(t *types.Type) string {
return fmt.Sprintf("etype=%d", et)
}
-// sprint_depchain prints a dependency chain of nodes into trace.
-// It is used by typecheck in the case of OLITERAL nodes
-// to print constant definition loops.
-func sprint_depchain(trace *string, stack []*Node, cur *Node, first *Node) {
- for i := len(stack) - 1; i >= 0; i-- {
- if n := stack[i]; n.Op == cur.Op {
- if n != first {
- sprint_depchain(trace, stack[:i], n, first)
- }
- *trace += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cur)
- return
+func cycleFor(start *Node) []*Node {
+ // Find the start node in typecheck_tcstack.
+ // We know that it must exist because each time we mark
+ // a node with n.SetTypecheck(2) we push it on the stack,
+ // and each time we mark a node with n.SetTypecheck(2) we
+ // pop it from the stack. We hit a cycle when we encounter
+ // a node marked 2 in which case is must be on the stack.
+ i := len(typecheck_tcstack) - 1
+ for i > 0 && typecheck_tcstack[i] != start {
+ i--
+ }
+
+ // collect all nodes with same Op
+ var cycle []*Node
+ for _, n := range typecheck_tcstack[i:] {
+ if n.Op == start.Op {
+ cycle = append(cycle, n)
}
}
+
+ return cycle
+}
+
+func cycleTrace(cycle []*Node) string {
+ var s string
+ for i, n := range cycle {
+ s += fmt.Sprintf("\n\t%v: %v uses %v", n.Line(), n, cycle[(i+1)%len(cycle)])
+ }
+ return s
}
var typecheck_tcstack []*Node
@@ -174,10 +195,20 @@ func typecheck(n *Node, top int) *Node {
}
case OTYPE:
+ // Only report a type cycle if we are expecting a type.
+ // Otherwise let other code report an error.
if top&Etype == Etype {
- var trace string
- sprint_depchain(&trace, typecheck_tcstack, n, n)
- yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, trace)
+ // A cycle containing only alias types is an error
+ // since it would expand indefinitely when aliases
+ // are substituted.
+ cycle := cycleFor(n)
+ for _, n := range cycle {
+ if n.Name != nil && !n.Name.Param.Alias {
+ lineno = lno
+ return n
+ }
+ }
+ yyerrorl(n.Pos, "invalid recursive type alias %v%s", n, cycleTrace(cycle))
}
case OLITERAL:
@@ -185,9 +216,7 @@ func typecheck(n *Node, top int) *Node {
yyerror("%v is not a type", n)
break
}
- var trace string
- sprint_depchain(&trace, typecheck_tcstack, n, n)
- yyerrorl(n.Pos, "constant definition loop%s", trace)
+ yyerrorl(n.Pos, "constant definition loop%s", cycleTrace(cycleFor(n)))
}
if nsavederrors+nerrors == 0 {
@@ -895,7 +924,7 @@ func typecheck1(n *Node, top int) *Node {
yyerror("%v undefined (cannot refer to unexported field or method %v)", n, n.Sym)
default:
- if mt := lookdot(n, t, 2); mt != nil { // Case-insensitive lookup.
+ if mt := lookdot(n, t, 2); mt != nil && visible(mt.Sym) { // Case-insensitive lookup.
yyerror("%v undefined (type %v has no field or method %v, but does have %v)", n, n.Left.Type, n.Sym, mt.Sym)
} else {
yyerror("%v undefined (type %v has no field or method %v)", n, n.Left.Type, n.Sym)
@@ -3108,7 +3137,11 @@ func typecheckcomplit(n *Node) *Node {
f := lookdot1(nil, l.Sym, t, t.Fields(), 0)
if f == nil {
if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
- yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
+ if visible(ci.Sym) {
+ yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
+ } else {
+ yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
+ }
continue
}
p, _ := dotpath(l.Sym, t, nil, true)
@@ -3155,6 +3188,11 @@ func typecheckcomplit(n *Node) *Node {
return n
}
+// visible reports whether sym is exported or locally defined.
+func visible(sym *types.Sym) bool {
+ return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
+}
+
// lvalue etc
func islvalue(n *Node) bool {
switch n.Op {
diff --git a/src/cmd/compile/internal/gc/walk.go b/src/cmd/compile/internal/gc/walk.go
index 591c8f3bfe..df7428a127 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -287,7 +287,6 @@ func walkstmt(n *Node) *Node {
walkstmtlist(n.Rlist.Slice())
case ORETURN:
- walkexprlist(n.List.Slice(), &n.Ninit)
if n.List.Len() == 0 {
break
}
@@ -317,6 +316,9 @@ func walkstmt(n *Node) *Node {
if samelist(rl, n.List.Slice()) {
// special return in disguise
+ // TODO(josharian, 1.12): is "special return" still relevant?
+ // Tests still pass w/o this. See comments on https://go-review.googlesource.com/c/go/+/118318
+ walkexprlist(n.List.Slice(), &n.Ninit)
n.List.Set(nil)
break
@@ -329,6 +331,7 @@ func walkstmt(n *Node) *Node {
n.List.Set(reorder3(ll))
break
}
+ walkexprlist(n.List.Slice(), &n.Ninit)
ll := ascompatte(nil, false, Curfn.Type.Results(), n.List.Slice(), 1, &n.Ninit)
n.List.Set(ll)
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 4bd9ade479..c7797d79e9 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -43,7 +43,7 @@ func Compile(f *Func) {
// Run all the passes
printFunc(f)
- f.HTMLWriter.WriteFunc("start", f)
+ f.HTMLWriter.WriteFunc("start", "start", f)
if BuildDump != "" && BuildDump == f.Name {
f.dumpFile("build")
}
@@ -86,7 +86,7 @@ func Compile(f *Func) {
f.Logf(" pass %s end %s\n", p.name, stats)
printFunc(f)
- f.HTMLWriter.WriteFunc(fmt.Sprintf("after %s <span class=\"stats\">%s</span>", phaseName, stats), f)
+ f.HTMLWriter.WriteFunc(phaseName, fmt.Sprintf("%s <span class=\"stats\">%s</span>", phaseName, stats), f)
}
if p.time || p.mem {
// Surround timing information w/ enough context to allow comparisons.
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
index 28694e435e..5a8634abd1 100644
--- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -397,11 +397,11 @@ func init() {
{name: "CMOVQNEF", argLength: 3, reg: gp21, asm: "CMOVQNE", resultInArg0: true},
{name: "CMOVQGTF", argLength: 3, reg: gp21, asm: "CMOVQHI", resultInArg0: true},
{name: "CMOVQGEF", argLength: 3, reg: gp21, asm: "CMOVQCC", resultInArg0: true},
- {name: "CMOVLEQF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true},
+ {name: "CMOVLEQF", argLength: 3, reg: gp21pax, asm: "CMOVLNE", resultInArg0: true},
{name: "CMOVLNEF", argLength: 3, reg: gp21, asm: "CMOVLNE", resultInArg0: true},
{name: "CMOVLGTF", argLength: 3, reg: gp21, asm: "CMOVLHI", resultInArg0: true},
{name: "CMOVLGEF", argLength: 3, reg: gp21, asm: "CMOVLCC", resultInArg0: true},
- {name: "CMOVWEQF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true},
+ {name: "CMOVWEQF", argLength: 3, reg: gp21pax, asm: "CMOVWNE", resultInArg0: true},
{name: "CMOVWNEF", argLength: 3, reg: gp21, asm: "CMOVWNE", resultInArg0: true},
{name: "CMOVWGTF", argLength: 3, reg: gp21, asm: "CMOVWHI", resultInArg0: true},
{name: "CMOVWGEF", argLength: 3, reg: gp21, asm: "CMOVWCC", resultInArg0: true},
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index 4714becd73..65b11c9980 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -829,14 +829,14 @@
(RSBconst [c] (SUBconst [d] x)) -> (RSBconst [int64(int32(c+d))] x)
(RSCconst [c] (ADDconst [d] x) flags) -> (RSCconst [int64(int32(c-d))] x flags)
(RSCconst [c] (SUBconst [d] x) flags) -> (RSCconst [int64(int32(c+d))] x flags)
-(SLLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)<<uint64(c))])
-(SRLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)>>uint64(c))])
+(SLLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(uint32(d)<<uint64(c)))])
+(SRLconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(uint32(d)>>uint64(c)))])
(SRAconst [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d)>>uint64(c))])
(MUL (MOVWconst [c]) (MOVWconst [d])) -> (MOVWconst [int64(int32(c*d))])
(MULA (MOVWconst [c]) (MOVWconst [d]) a) -> (ADDconst [int64(int32(c*d))] a)
(MULS (MOVWconst [c]) (MOVWconst [d]) a) -> (SUBconst [int64(int32(c*d))] a)
-(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)/uint32(d))])
-(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(uint32(c)%uint32(d))])
+(Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(uint32(c)/uint32(d)))])
+(Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d]))) -> (MOVWconst [int64(int32(uint32(c)%uint32(d)))])
(ANDconst [c] (MOVWconst [d])) -> (MOVWconst [c&d])
(ANDconst [c] (ANDconst [d] x)) -> (ANDconst [c&d] x)
(ORconst [c] (MOVWconst [d])) -> (MOVWconst [c|d])
@@ -853,7 +853,7 @@
(MOVWreg (MOVWconst [c])) -> (MOVWconst [c])
// BFX: Width = c >> 8, LSB = c & 0xff, result = d << (32 - Width - LSB) >> (32 - Width)
(BFX [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(d)<<(32-uint32(c&0xff)-uint32(c>>8))>>(32-uint32(c>>8)))])
-(BFXU [c] (MOVWconst [d])) -> (MOVWconst [int64(uint32(d)<<(32-uint32(c&0xff)-uint32(c>>8))>>(32-uint32(c>>8)))])
+(BFXU [c] (MOVWconst [d])) -> (MOVWconst [int64(int32(uint32(d)<<(32-uint32(c&0xff)-uint32(c>>8))>>(32-uint32(c>>8))))])
// absorb shifts into ops
(ADD x (SLLconst [c] y)) -> (ADDshiftLL x y [c])
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index b5eeb96468..a7e747e6e7 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -540,8 +540,12 @@
(AtomicCompareAndSwap32 ptr old new_ mem) -> (LoweredAtomicCas32 ptr old new_ mem)
(AtomicCompareAndSwap64 ptr old new_ mem) -> (LoweredAtomicCas64 ptr old new_ mem)
-(AtomicAnd8 ptr val mem) -> (LoweredAtomicAnd8 ptr val mem)
-(AtomicOr8 ptr val mem) -> (LoweredAtomicOr8 ptr val mem)
+// Currently the updated value is not used, but we need a register to temporarily hold it.
+(AtomicAnd8 ptr val mem) -> (Select1 (LoweredAtomicAnd8 ptr val mem))
+(AtomicOr8 ptr val mem) -> (Select1 (LoweredAtomicOr8 ptr val mem))
+
+(AtomicAdd32Variant ptr val mem) -> (LoweredAtomicAdd32Variant ptr val mem)
+(AtomicAdd64Variant ptr val mem) -> (LoweredAtomicAdd64Variant ptr val mem)
// Write barrier.
(WB {fn} destptr srcptr mem) -> (LoweredWB {fn} destptr srcptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index b54de53f59..c87c18f3fb 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -578,6 +578,13 @@ func init() {
{name: "LoweredAtomicAdd64", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
{name: "LoweredAtomicAdd32", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
+ // atomic add variant.
+ // *arg0 += arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero.
+ // LDADDAL (Rarg0), Rarg1, Rout
+ // ADD Rarg1, Rout
+ {name: "LoweredAtomicAdd64Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicAdd32Variant", argLength: 3, reg: gpxchg, resultNotInArgs: true, faultOnNilArg0: true, hasSideEffects: true},
+
// atomic compare and swap.
// arg0 = pointer, arg1 = old value, arg2 = new value, arg3 = memory. auxint must be zero.
// if *arg0 == arg1 {
@@ -596,13 +603,13 @@ func init() {
{name: "LoweredAtomicCas32", argLength: 4, reg: gpcas, resultNotInArgs: true, clobberFlags: true, faultOnNilArg0: true, hasSideEffects: true},
// atomic and/or.
- // *arg0 &= (|=) arg1. arg2=mem. returns memory. auxint must be zero.
- // LDAXRB (Rarg0), Rtmp
- // AND/OR Rarg1, Rtmp
- // STLXRB Rtmp, (Rarg0), Rtmp
+ // *arg0 &= (|=) arg1. arg2=mem. returns <new content of *arg0, memory>. auxint must be zero.
+ // LDAXRB (Rarg0), Rout
+ // AND/OR Rarg1, Rout
+ // STLXRB Rout, (Rarg0), Rtmp
// CBNZ Rtmp, -3(PC)
- {name: "LoweredAtomicAnd8", argLength: 3, reg: gpstore, asm: "AND", faultOnNilArg0: true, hasSideEffects: true},
- {name: "LoweredAtomicOr8", argLength: 3, reg: gpstore, asm: "ORR", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicAnd8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "AND", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true},
+ {name: "LoweredAtomicOr8", argLength: 3, reg: gpxchg, resultNotInArgs: true, asm: "ORR", typ: "(UInt8,Mem)", faultOnNilArg0: true, hasSideEffects: true},
// LoweredWB invokes runtime.gcWriteBarrier. arg0=destptr, arg1=srcptr, arg2=mem, aux=runtime.gcWriteBarrier
// It saves all GP registers if necessary,
diff --git a/src/cmd/compile/internal/ssa/gen/Wasm.rules b/src/cmd/compile/internal/ssa/gen/Wasm.rules
index 18c208cccb..272b260cb7 100644
--- a/src/cmd/compile/internal/ssa/gen/Wasm.rules
+++ b/src/cmd/compile/internal/ssa/gen/Wasm.rules
@@ -390,6 +390,7 @@
(I64AddConst [0] x) -> x
(I64Eqz (I64Eqz (I64Eqz x))) -> (I64Eqz x)
+// folding offset into load/store
((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off] (I64AddConst [off2] ptr) mem)
&& isU32Bit(off+off2) ->
((I64Load|I64Load32U|I64Load32S|I64Load16U|I64Load16S|I64Load8U|I64Load8S) [off+off2] ptr mem)
@@ -397,3 +398,7 @@
((I64Store|I64Store32|I64Store16|I64Store8) [off] (I64AddConst [off2] ptr) val mem)
&& isU32Bit(off+off2) ->
((I64Store|I64Store32|I64Store16|I64Store8) [off+off2] ptr val mem)
+
+// folding offset into address
+(I64AddConst [off] (LoweredAddr {sym} [off2] base)) && isU32Bit(off+off2) ->
+ (LoweredAddr {sym} [off+off2] base)
diff --git a/src/cmd/compile/internal/ssa/gen/WasmOps.go b/src/cmd/compile/internal/ssa/gen/WasmOps.go
index c8d7677355..9b4f66d3f1 100644
--- a/src/cmd/compile/internal/ssa/gen/WasmOps.go
+++ b/src/cmd/compile/internal/ssa/gen/WasmOps.go
@@ -103,7 +103,7 @@ func init() {
{name: "LoweredClosureCall", argLength: 3, reg: regInfo{inputs: []regMask{gp, gp, 0}, clobbers: callerSave}, aux: "Int64", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "LoweredInterCall", argLength: 2, reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64", call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem
- {name: "LoweredAddr", argLength: 1, reg: gp11, aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // returns base+aux, arg0=base
+ {name: "LoweredAddr", argLength: 1, reg: gp11, aux: "SymOff", rematerializeable: true, symEffect: "Addr"}, // returns base+aux+auxint, arg0=base
{name: "LoweredMove", argLength: 3, reg: regInfo{inputs: []regMask{gp, gp}}, aux: "Int64"}, // large move. arg0=dst, arg1=src, arg2=mem, auxint=len/8, returns mem
{name: "LoweredZero", argLength: 2, reg: regInfo{inputs: []regMask{gp}}, aux: "Int64"}, // large zeroing. arg0=start, arg1=mem, auxint=len/8, returns mem
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 13581452e7..07d93ac073 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -515,6 +515,13 @@ var genericOps = []opData{
{name: "AtomicAnd8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 &= arg1. arg2=memory. Returns memory.
{name: "AtomicOr8", argLength: 3, typ: "Mem", hasSideEffects: true}, // *arg0 |= arg1. arg2=memory. Returns memory.
+ // Atomic operation variants
+ // These variants have the same semantics as above atomic operations.
+ // But they are used for generating more efficient code on certain modern machines, with run-time CPU feature detection.
+ // Currently, they are used on ARM64 only.
+ {name: "AtomicAdd32Variant", argLength: 3, typ: "(UInt32,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+ {name: "AtomicAdd64Variant", argLength: 3, typ: "(UInt64,Mem)", hasSideEffects: true}, // Do *arg0 += arg1. arg2=memory. Returns sum and new memory.
+
// Clobber experiment op
{name: "Clobber", argLength: 0, typ: "Void", aux: "SymOff", symEffect: "None"}, // write an invalid pointer value to the given pointer slot of a stack variable
}
diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go
index 85d97ba497..15d64d63e9 100644
--- a/src/cmd/compile/internal/ssa/html.go
+++ b/src/cmd/compile/internal/ssa/html.go
@@ -38,6 +38,11 @@ func (w *HTMLWriter) start(name string) {
<meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
<style>
+body {
+ font-size: 14px;
+ font-family: Arial, sans-serif;
+}
+
#helplink {
margin-bottom: 15px;
display: block;
@@ -66,6 +71,32 @@ th, td {
padding: 5px;
}
+td > h2 {
+ cursor: pointer;
+ font-size: 120%;
+}
+
+td.collapsed {
+ font-size: 12px;
+ width: 12px;
+ border: 0px;
+ padding: 0;
+ cursor: pointer;
+ background: #fafafa;
+}
+
+td.collapsed div {
+ -moz-transform: rotate(-90.0deg); /* FF3.5+ */
+ -o-transform: rotate(-90.0deg); /* Opera 10.5 */
+ -webkit-transform: rotate(-90.0deg); /* Saf3.1+, Chrome */
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083); /* IE6,IE7 */
+ -ms-filter: "progid:DXImageTransform.Microsoft.BasicImage(rotation=0.083)"; /* IE8 */
+ margin-top: 10.3em;
+ margin-left: -10em;
+ margin-right: -10em;
+ text-align: right;
+}
+
td.ssa-prog {
width: 600px;
word-wrap: break-word;
@@ -131,14 +162,18 @@ dd.ssa-prog {
font-size: 11px;
}
-.highlight-yellow { background-color: yellow; }
.highlight-aquamarine { background-color: aquamarine; }
.highlight-coral { background-color: coral; }
.highlight-lightpink { background-color: lightpink; }
.highlight-lightsteelblue { background-color: lightsteelblue; }
.highlight-palegreen { background-color: palegreen; }
-.highlight-powderblue { background-color: powderblue; }
+.highlight-skyblue { background-color: skyblue; }
.highlight-lightgray { background-color: lightgray; }
+.highlight-yellow { background-color: yellow; }
+.highlight-lime { background-color: lime; }
+.highlight-khaki { background-color: khaki; }
+.highlight-aqua { background-color: aqua; }
+.highlight-salmon { background-color: salmon; }
.outline-blue { outline: blue solid 2px; }
.outline-red { outline: red solid 2px; }
@@ -147,6 +182,10 @@ dd.ssa-prog {
.outline-fuchsia { outline: fuchsia solid 2px; }
.outline-sienna { outline: sienna solid 2px; }
.outline-gold { outline: gold solid 2px; }
+.outline-orangered { outline: orangered solid 2px; }
+.outline-teal { outline: teal solid 2px; }
+.outline-maroon { outline: maroon solid 2px; }
+.outline-black { outline: black solid 2px; }
</style>
@@ -158,8 +197,13 @@ var highlights = [
"highlight-lightpink",
"highlight-lightsteelblue",
"highlight-palegreen",
+ "highlight-skyblue",
"highlight-lightgray",
- "highlight-yellow"
+ "highlight-yellow",
+ "highlight-lime",
+ "highlight-khaki",
+ "highlight-aqua",
+ "highlight-salmon"
];
// state: which value is highlighted this color?
@@ -176,7 +220,11 @@ var outlines = [
"outline-darkolivegreen",
"outline-fuchsia",
"outline-sienna",
- "outline-gold"
+ "outline-gold",
+ "outline-orangered",
+ "outline-teal",
+ "outline-maroon",
+ "outline-black"
];
// state: which value is outlined this color?
@@ -263,6 +311,56 @@ window.onload = function() {
for (var i = 0; i < ssablocks.length; i++) {
ssablocks[i].addEventListener('click', ssaBlockClicked);
}
+ var expandedDefault = [
+ "start",
+ "deadcode",
+ "opt",
+ "lower",
+ "late deadcode",
+ "regalloc",
+ "genssa",
+ ]
+ function isExpDefault(id) {
+ for (var i = 0; i < expandedDefault.length; i++) {
+ if (id.startsWith(expandedDefault[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+ function toggler(phase) {
+ return function() {
+ toggle_cell(phase+'-col');
+ toggle_cell(phase+'-exp');
+ };
+ }
+ function toggle_cell(id) {
+ var e = document.getElementById(id);
+ if(e.style.display == 'table-cell')
+ e.style.display = 'none';
+ else
+ e.style.display = 'table-cell';
+ }
+
+ var td = document.getElementsByTagName("td");
+ for (var i = 0; i < td.length; i++) {
+ var id = td[i].id;
+ var def = isExpDefault(id);
+ var phase = id.substr(0, id.length-4);
+ if (id.endsWith("-exp")) {
+ var h2 = td[i].getElementsByTagName("h2");
+ if (h2 && h2[0]) {
+ h2[0].addEventListener('click', toggler(phase));
+ }
+ } else {
+ td[i].addEventListener('click', toggler(phase));
+ }
+ if (id.endsWith("-col") && def || id.endsWith("-exp") && !def) {
+ td[i].style.display = 'none';
+ continue
+ }
+ td[i].style.display = 'table-cell';
+ }
};
function toggle_visibility(id) {
@@ -316,24 +414,28 @@ func (w *HTMLWriter) Close() {
}
// WriteFunc writes f in a column headed by title.
-func (w *HTMLWriter) WriteFunc(title string, f *Func) {
+func (w *HTMLWriter) WriteFunc(phase, title string, f *Func) {
if w == nil {
return // avoid generating HTML just to discard it
}
- w.WriteColumn(title, "", f.HTML())
+ w.WriteColumn(phase, title, "", f.HTML())
// TODO: Add visual representation of f's CFG.
}
// WriteColumn writes raw HTML in a column headed by title.
// It is intended for pre- and post-compilation log output.
-func (w *HTMLWriter) WriteColumn(title, class, html string) {
+func (w *HTMLWriter) WriteColumn(phase, title, class, html string) {
if w == nil {
return
}
+ id := strings.Replace(phase, " ", "-", -1)
+ // collapsed column
+ w.Printf("<td id=\"%v-col\" class=\"collapsed\"><div>%v</div></td>", id, phase)
+
if class == "" {
- w.WriteString("<td>")
+ w.Printf("<td id=\"%v-exp\">", id)
} else {
- w.WriteString("<td class=\"" + class + "\">")
+ w.Printf("<td id=\"%v-exp\" class=\"%v\">", id, class)
}
w.WriteString("<h2>" + title + "</h2>")
w.WriteString(html)
diff --git a/src/cmd/compile/internal/ssa/loopbce.go b/src/cmd/compile/internal/ssa/loopbce.go
index 0c09de0bfc..2ab05711ad 100644
--- a/src/cmd/compile/internal/ssa/loopbce.go
+++ b/src/cmd/compile/internal/ssa/loopbce.go
@@ -1,3 +1,7 @@
+// Copyright 2018 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 ssa
import "fmt"
@@ -154,7 +158,7 @@ nextb:
// if the increment is ±1 or when the limits are constants.
if inc.AuxInt != 1 && inc.AuxInt != -1 {
ok := false
- if min.Op == OpConst64 && max.Op == OpConst64 {
+ if min.Op == OpConst64 && max.Op == OpConst64 && inc.AuxInt != 0 {
if max.AuxInt > min.AuxInt && max.AuxInt%inc.AuxInt == min.AuxInt%inc.AuxInt { // handle overflow
ok = true
}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 4e12132aa5..4924947d8b 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -1275,6 +1275,8 @@ const (
OpARM64LoweredAtomicExchange32
OpARM64LoweredAtomicAdd64
OpARM64LoweredAtomicAdd32
+ OpARM64LoweredAtomicAdd64Variant
+ OpARM64LoweredAtomicAdd32Variant
OpARM64LoweredAtomicCas64
OpARM64LoweredAtomicCas32
OpARM64LoweredAtomicAnd8
@@ -2287,6 +2289,8 @@ const (
OpAtomicCompareAndSwap64
OpAtomicAnd8
OpAtomicOr8
+ OpAtomicAdd32Variant
+ OpAtomicAdd64Variant
OpClobber
)
@@ -7952,11 +7956,12 @@ var opcodeTable = [...]opInfo{
asm: x86.ACMOVLNE,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
+ clobbers: 1, // AX
outputs: []outputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -8012,11 +8017,12 @@ var opcodeTable = [...]opInfo{
asm: x86.ACMOVWNE,
reg: regInfo{
inputs: []inputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
{1, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
+ clobbers: 1, // AX
outputs: []outputInfo{
- {0, 65519}, // AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
+ {0, 65518}, // CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15
},
},
},
@@ -16723,6 +16729,38 @@ var opcodeTable = [...]opInfo{
},
},
{
+ name: "LoweredAtomicAdd64Variant",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
+ },
+ },
+ {
+ name: "LoweredAtomicAdd32Variant",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ reg: regInfo{
+ inputs: []inputInfo{
+ {1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
+ {0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
+ },
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
+ },
+ },
+ {
name: "LoweredAtomicCas64",
argLen: 4,
resultNotInArgs: true,
@@ -16759,29 +16797,37 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "LoweredAtomicAnd8",
- argLen: 3,
- faultOnNilArg0: true,
- hasSideEffects: true,
- asm: arm64.AAND,
+ name: "LoweredAtomicAnd8",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ asm: arm64.AAND,
reg: regInfo{
inputs: []inputInfo{
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
{0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
},
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
},
},
{
- name: "LoweredAtomicOr8",
- argLen: 3,
- faultOnNilArg0: true,
- hasSideEffects: true,
- asm: arm64.AORR,
+ name: "LoweredAtomicOr8",
+ argLen: 3,
+ resultNotInArgs: true,
+ faultOnNilArg0: true,
+ hasSideEffects: true,
+ asm: arm64.AORR,
reg: regInfo{
inputs: []inputInfo{
{1, 805044223}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30
{0, 9223372038733561855}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 g R30 SP SB
},
+ outputs: []outputInfo{
+ {0, 670826495}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R13 R14 R15 R16 R17 R19 R20 R21 R22 R23 R24 R25 R26 R30
+ },
},
},
{
@@ -27818,6 +27864,18 @@ var opcodeTable = [...]opInfo{
generic: true,
},
{
+ name: "AtomicAdd32Variant",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
+ {
+ name: "AtomicAdd64Variant",
+ argLen: 3,
+ hasSideEffects: true,
+ generic: true,
+ },
+ {
name: "Clobber",
auxType: auxSymOff,
argLen: 0,
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 2622913eae..1eb32285cd 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -4044,7 +4044,7 @@ func rewriteValueARM_OpARMBFX_0(v *Value) bool {
func rewriteValueARM_OpARMBFXU_0(v *Value) bool {
// match: (BFXU [c] (MOVWconst [d]))
// cond:
- // result: (MOVWconst [int64(uint32(d)<<(32-uint32(c&0xff)-uint32(c>>8))>>(32-uint32(c>>8)))])
+ // result: (MOVWconst [int64(int32(uint32(d)<<(32-uint32(c&0xff)-uint32(c>>8))>>(32-uint32(c>>8))))])
for {
c := v.AuxInt
v_0 := v.Args[0]
@@ -4053,7 +4053,7 @@ func rewriteValueARM_OpARMBFXU_0(v *Value) bool {
}
d := v_0.AuxInt
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(uint32(d) << (32 - uint32(c&0xff) - uint32(c>>8)) >> (32 - uint32(c>>8)))
+ v.AuxInt = int64(int32(uint32(d) << (32 - uint32(c&0xff) - uint32(c>>8)) >> (32 - uint32(c>>8))))
return true
}
return false
@@ -14103,7 +14103,7 @@ func rewriteValueARM_OpARMSLL_0(v *Value) bool {
func rewriteValueARM_OpARMSLLconst_0(v *Value) bool {
// match: (SLLconst [c] (MOVWconst [d]))
// cond:
- // result: (MOVWconst [int64(uint32(d)<<uint64(c))])
+ // result: (MOVWconst [int64(int32(uint32(d)<<uint64(c)))])
for {
c := v.AuxInt
v_0 := v.Args[0]
@@ -14112,7 +14112,7 @@ func rewriteValueARM_OpARMSLLconst_0(v *Value) bool {
}
d := v_0.AuxInt
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(uint32(d) << uint64(c))
+ v.AuxInt = int64(int32(uint32(d) << uint64(c)))
return true
}
return false
@@ -14274,7 +14274,7 @@ func rewriteValueARM_OpARMSRL_0(v *Value) bool {
func rewriteValueARM_OpARMSRLconst_0(v *Value) bool {
// match: (SRLconst [c] (MOVWconst [d]))
// cond:
- // result: (MOVWconst [int64(uint32(d)>>uint64(c))])
+ // result: (MOVWconst [int64(int32(uint32(d)>>uint64(c)))])
for {
c := v.AuxInt
v_0 := v.Args[0]
@@ -14283,7 +14283,7 @@ func rewriteValueARM_OpARMSRLconst_0(v *Value) bool {
}
d := v_0.AuxInt
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(uint32(d) >> uint64(c))
+ v.AuxInt = int64(int32(uint32(d) >> uint64(c)))
return true
}
// match: (SRLconst (SLLconst x [c]) [d])
@@ -21295,7 +21295,7 @@ func rewriteValueARM_OpSelect0_0(v *Value) bool {
}
// match: (Select0 (CALLudiv (MOVWconst [c]) (MOVWconst [d])))
// cond:
- // result: (MOVWconst [int64(uint32(c)/uint32(d))])
+ // result: (MOVWconst [int64(int32(uint32(c)/uint32(d)))])
for {
v_0 := v.Args[0]
if v_0.Op != OpARMCALLudiv {
@@ -21313,7 +21313,7 @@ func rewriteValueARM_OpSelect0_0(v *Value) bool {
}
d := v_0_1.AuxInt
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(uint32(c) / uint32(d))
+ v.AuxInt = int64(int32(uint32(c) / uint32(d)))
return true
}
return false
@@ -21364,7 +21364,7 @@ func rewriteValueARM_OpSelect1_0(v *Value) bool {
}
// match: (Select1 (CALLudiv (MOVWconst [c]) (MOVWconst [d])))
// cond:
- // result: (MOVWconst [int64(uint32(c)%uint32(d))])
+ // result: (MOVWconst [int64(int32(uint32(c)%uint32(d)))])
for {
v_0 := v.Args[0]
if v_0.Op != OpARMCALLudiv {
@@ -21382,7 +21382,7 @@ func rewriteValueARM_OpSelect1_0(v *Value) bool {
}
d := v_0_1.AuxInt
v.reset(OpARMMOVWconst)
- v.AuxInt = int64(uint32(c) % uint32(d))
+ v.AuxInt = int64(int32(uint32(c) % uint32(d)))
return true
}
return false
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index f538011198..d039c731d3 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -341,8 +341,12 @@ func rewriteValueARM64(v *Value) bool {
return rewriteValueARM64_OpAndB_0(v)
case OpAtomicAdd32:
return rewriteValueARM64_OpAtomicAdd32_0(v)
+ case OpAtomicAdd32Variant:
+ return rewriteValueARM64_OpAtomicAdd32Variant_0(v)
case OpAtomicAdd64:
return rewriteValueARM64_OpAtomicAdd64_0(v)
+ case OpAtomicAdd64Variant:
+ return rewriteValueARM64_OpAtomicAdd64Variant_0(v)
case OpAtomicAnd8:
return rewriteValueARM64_OpAtomicAnd8_0(v)
case OpAtomicCompareAndSwap32:
@@ -25908,6 +25912,22 @@ func rewriteValueARM64_OpAtomicAdd32_0(v *Value) bool {
return true
}
}
+func rewriteValueARM64_OpAtomicAdd32Variant_0(v *Value) bool {
+ // match: (AtomicAdd32Variant ptr val mem)
+ // cond:
+ // result: (LoweredAtomicAdd32Variant ptr val mem)
+ for {
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpARM64LoweredAtomicAdd32Variant)
+ v.AddArg(ptr)
+ v.AddArg(val)
+ v.AddArg(mem)
+ return true
+ }
+}
func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool {
// match: (AtomicAdd64 ptr val mem)
// cond:
@@ -25924,22 +25944,44 @@ func rewriteValueARM64_OpAtomicAdd64_0(v *Value) bool {
return true
}
}
-func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool {
- // match: (AtomicAnd8 ptr val mem)
+func rewriteValueARM64_OpAtomicAdd64Variant_0(v *Value) bool {
+ // match: (AtomicAdd64Variant ptr val mem)
// cond:
- // result: (LoweredAtomicAnd8 ptr val mem)
+ // result: (LoweredAtomicAdd64Variant ptr val mem)
for {
_ = v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
mem := v.Args[2]
- v.reset(OpARM64LoweredAtomicAnd8)
+ v.reset(OpARM64LoweredAtomicAdd64Variant)
v.AddArg(ptr)
v.AddArg(val)
v.AddArg(mem)
return true
}
}
+func rewriteValueARM64_OpAtomicAnd8_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
+ // match: (AtomicAnd8 ptr val mem)
+ // cond:
+ // result: (Select1 (LoweredAtomicAnd8 ptr val mem))
+ for {
+ _ = v.Args[2]
+ ptr := v.Args[0]
+ val := v.Args[1]
+ mem := v.Args[2]
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicAnd8, types.NewTuple(typ.UInt8, types.TypeMem))
+ v0.AddArg(ptr)
+ v0.AddArg(val)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ return true
+ }
+}
func rewriteValueARM64_OpAtomicCompareAndSwap32_0(v *Value) bool {
// match: (AtomicCompareAndSwap32 ptr old new_ mem)
// cond:
@@ -26051,18 +26093,24 @@ func rewriteValueARM64_OpAtomicLoadPtr_0(v *Value) bool {
}
}
func rewriteValueARM64_OpAtomicOr8_0(v *Value) bool {
+ b := v.Block
+ _ = b
+ typ := &b.Func.Config.Types
+ _ = typ
// match: (AtomicOr8 ptr val mem)
// cond:
- // result: (LoweredAtomicOr8 ptr val mem)
+ // result: (Select1 (LoweredAtomicOr8 ptr val mem))
for {
_ = v.Args[2]
ptr := v.Args[0]
val := v.Args[1]
mem := v.Args[2]
- v.reset(OpARM64LoweredAtomicOr8)
- v.AddArg(ptr)
- v.AddArg(val)
- v.AddArg(mem)
+ v.reset(OpSelect1)
+ v0 := b.NewValue0(v.Pos, OpARM64LoweredAtomicOr8, types.NewTuple(typ.UInt8, types.TypeMem))
+ v0.AddArg(ptr)
+ v0.AddArg(val)
+ v0.AddArg(mem)
+ v.AddArg(v0)
return true
}
}
diff --git a/src/cmd/compile/internal/ssa/rewriteWasm.go b/src/cmd/compile/internal/ssa/rewriteWasm.go
index f3648ebca1..26dd254952 100644
--- a/src/cmd/compile/internal/ssa/rewriteWasm.go
+++ b/src/cmd/compile/internal/ssa/rewriteWasm.go
@@ -5210,6 +5210,27 @@ func rewriteValueWasm_OpWasmI64AddConst_0(v *Value) bool {
v.AddArg(x)
return true
}
+ // match: (I64AddConst [off] (LoweredAddr {sym} [off2] base))
+ // cond: isU32Bit(off+off2)
+ // result: (LoweredAddr {sym} [off+off2] base)
+ for {
+ off := v.AuxInt
+ v_0 := v.Args[0]
+ if v_0.Op != OpWasmLoweredAddr {
+ break
+ }
+ off2 := v_0.AuxInt
+ sym := v_0.Aux
+ base := v_0.Args[0]
+ if !(isU32Bit(off + off2)) {
+ break
+ }
+ v.reset(OpWasmLoweredAddr)
+ v.AuxInt = off + off2
+ v.Aux = sym
+ v.AddArg(base)
+ return true
+ }
return false
}
func rewriteValueWasm_OpWasmI64And_0(v *Value) bool {
diff --git a/src/cmd/compile/internal/ssa/schedule.go b/src/cmd/compile/internal/ssa/schedule.go
index f1783a9532..c62c0c47e2 100644
--- a/src/cmd/compile/internal/ssa/schedule.go
+++ b/src/cmd/compile/internal/ssa/schedule.go
@@ -310,6 +310,7 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value
// A constant bound allows this to be stack-allocated. 64 is
// enough to cover almost every storeOrder call.
stores := make([]*Value, 0, 64)
+ var vardefs map[interface{}]*Value // OpAddr must depend on Vardef for Node
hasNilCheck := false
sset.clear() // sset is the set of stores that are used in other values
for _, v := range values {
@@ -323,6 +324,12 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value
if v.Op == OpNilCheck {
hasNilCheck = true
}
+ if v.Op == OpVarDef {
+ if vardefs == nil { // Lazy init, not all blocks have vardefs
+ vardefs = make(map[interface{}]*Value)
+ }
+ vardefs[v.Aux] = v
+ }
}
if len(stores) == 0 || !hasNilCheck && f.pass.name == "nilcheckelim" {
// there is no store, the order does not matter
@@ -386,7 +393,20 @@ func storeOrder(values []*Value, sset *sparseSet, storeNumber []int32) []*Value
stack = stack[:len(stack)-1]
continue
}
-
+ if w.Op == OpAddr {
+ // OpAddr depends only on relevant VarDef
+ vn := int32(0)
+ if vardefs != nil {
+ if a := vardefs[w.Aux]; a != nil { // if nil, it is in some other block, or global or arg
+ vn = storeNumber[a.ID]
+ }
+ }
+ vn += 2
+ storeNumber[w.ID] = vn
+ count[vn]++
+ stack = stack[:len(stack)-1]
+ continue
+ }
max := int32(0) // latest store dependency
argsdone := true
for _, a := range w.Args {
diff --git a/src/cmd/compile/internal/types/scope.go b/src/cmd/compile/internal/types/scope.go
index 156174746f..40d3d86ef1 100644
--- a/src/cmd/compile/internal/types/scope.go
+++ b/src/cmd/compile/internal/types/scope.go
@@ -80,15 +80,24 @@ func IsDclstackValid() bool {
// PkgDef returns the definition associated with s at package scope.
func (s *Sym) PkgDef() *Node {
+ return *s.pkgDefPtr()
+}
+
+// SetPkgDef sets the definition associated with s at package scope.
+func (s *Sym) SetPkgDef(n *Node) {
+ *s.pkgDefPtr() = n
+}
+
+func (s *Sym) pkgDefPtr() **Node {
// Look for outermost saved declaration, which must be the
// package scope definition, if present.
for _, d := range dclstack {
if s == d.sym {
- return d.def
+ return &d.def
}
}
// Otherwise, the declaration hasn't been shadowed within a
// function scope.
- return s.Def
+ return &s.Def
}
diff --git a/src/cmd/compile/internal/wasm/ssa.go b/src/cmd/compile/internal/wasm/ssa.go
index 8daf749a12..d82b1f7953 100644
--- a/src/cmd/compile/internal/wasm/ssa.go
+++ b/src/cmd/compile/internal/wasm/ssa.go
@@ -232,19 +232,13 @@ func ssaGenValueOnStack(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpWasmLoweredAddr:
p := s.Prog(wasm.AGet)
- switch n := v.Aux.(type) {
+ p.From.Type = obj.TYPE_ADDR
+ switch v.Aux.(type) {
case *obj.LSym:
- p.From = obj.Addr{Type: obj.TYPE_ADDR, Name: obj.NAME_EXTERN, Sym: n}
+ gc.AddAux(&p.From, v)
case *gc.Node:
- p.From = obj.Addr{
- Type: obj.TYPE_ADDR,
- Name: obj.NAME_AUTO,
- Reg: v.Args[0].Reg(),
- Offset: n.Xoffset,
- }
- if n.Class() == gc.PPARAM || n.Class() == gc.PPARAMOUT {
- p.From.Name = obj.NAME_PARAM
- }
+ p.From.Reg = v.Args[0].Reg()
+ gc.AddAux(&p.From, v)
default:
panic("wasm: bad LoweredAddr")
}
diff --git a/src/cmd/cover/cover_test.go b/src/cmd/cover/cover_test.go
index ec80f94e59..c818819c39 100644
--- a/src/cmd/cover/cover_test.go
+++ b/src/cmd/cover/cover_test.go
@@ -18,7 +18,6 @@ import (
"os/exec"
"path/filepath"
"regexp"
- "runtime"
"strings"
"testing"
)
@@ -267,9 +266,6 @@ func TestCoverFunc(t *testing.T) {
// Check that cover produces correct HTML.
// Issue #25767.
func TestCoverHTML(t *testing.T) {
- if _, err := exec.LookPath("diff"); err != nil {
- t.Skipf("skip test on %s: diff command is required", runtime.GOOS)
- }
testenv.MustHaveGoBuild(t)
if !*debug {
defer os.Remove(testcover)
@@ -307,16 +303,30 @@ func TestCoverHTML(t *testing.T) {
in = false
}
}
- if err := ioutil.WriteFile(htmlHTML, out.Bytes(), 0644); err != nil {
- t.Fatal(err)
+ golden, err := ioutil.ReadFile(htmlGolden)
+ if err != nil {
+ t.Fatalf("reading golden file: %v", err)
}
- diff := "diff"
- if runtime.GOOS == "plan9" {
- diff = "/bin/ape/diff"
+ // Ignore white space differences.
+ // Break into lines, then compare by breaking into words.
+ goldenLines := strings.Split(string(golden), "\n")
+ outLines := strings.Split(out.String(), "\n")
+ // Compare at the line level, stopping at first different line so
+ // we don't generate tons of output if there's an inserted or deleted line.
+ for i, goldenLine := range goldenLines {
+ if i > len(outLines) {
+ t.Fatalf("output shorter than golden; stops before line %d: %s\n", i+1, goldenLine)
+ }
+ // Convert all white space to simple spaces, for easy comparison.
+ goldenLine = strings.Join(strings.Fields(goldenLine), " ")
+ outLine := strings.Join(strings.Fields(outLines[i]), " ")
+ if outLine != goldenLine {
+ t.Fatalf("line %d differs: got:\n\t%s\nwant:\n\t%s", i+1, outLine, goldenLine)
+ }
+ }
+ if len(goldenLines) != len(outLines) {
+ t.Fatalf("output longer than golden; first extra output line %d: %q\n", len(goldenLines)+1, outLines[len(goldenLines)])
}
- // diff -uw testdata/html/html.html testdata/html/html.golden
- cmd = exec.Command(diff, "-u", "-w", htmlHTML, htmlGolden)
- run(cmd, t)
}
func run(c *exec.Cmd, t *testing.T) {
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index effea903e9..616e76dfe7 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -67,6 +67,7 @@ var okgoarch = []string{
"mips64le",
"ppc64",
"ppc64le",
+ "riscv64",
"s390x",
"wasm",
}
@@ -1393,6 +1394,7 @@ var cgoEnabled = map[string]bool{
"linux/mipsle": true,
"linux/mips64": true,
"linux/mips64le": true,
+ "linux/riscv64": true,
"linux/s390x": true,
"android/386": true,
"android/amd64": true,
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index 889fd02aaf..94b7587026 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -80,6 +80,8 @@ var bootstrapDirs = []string{
"cmd/link/internal/s390x",
"cmd/link/internal/sym",
"cmd/link/internal/x86",
+ "compress/flate",
+ "compress/zlib",
"cmd/link/internal/wasm",
"container/heap",
"debug/dwarf",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index a1c470cc97..5be4bcfa65 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -308,11 +308,10 @@ func (t *tester) registerStdTest(pkg string) {
timeoutSec := 180
for _, pkg := range stdMatches {
if pkg == "cmd/go" {
- timeoutSec *= 2
+ timeoutSec *= 3
break
}
}
-
args := []string{
"test",
short(),
@@ -325,6 +324,8 @@ func (t *tester) registerStdTest(pkg string) {
}
if t.compileOnly {
args = append(args, "-run=^$")
+ } else if goos == "js" && goarch == "wasm" {
+ args = append(args, "-run=^Test") // exclude examples; Issue 25913
}
args = append(args, stdMatches...)
cmd := exec.Command("go", args...)
@@ -355,7 +356,8 @@ func (t *tester) registerRaceBenchTest(pkg string) {
"test",
short(),
"-race",
- "-run=^$", // nothing. only benchmarks.
+ t.timeout(1200), // longer timeout for race with benchmarks
+ "-run=^$", // nothing. only benchmarks.
"-benchtime=.1s",
"-cpu=4",
}
@@ -449,7 +451,7 @@ func (t *tester) registerTests() {
}
// Runtime CPU tests.
- if !t.compileOnly {
+ if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1
testName := "runtime:cpu124"
t.tests = append(t.tests, distTest{
name: testName,
@@ -490,9 +492,9 @@ func (t *tester) registerTests() {
// On the builders only, test that a moved GOROOT still works.
// Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
// in the unmoved GOROOT.
- // Fails on Android with an exec format error.
+ // Fails on Android and js/wasm with an exec format error.
// Fails on plan9 with "cannot find GOROOT" (issue #21016).
- if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" {
+ if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
t.tests = append(t.tests, distTest{
name: "moved_goroot",
heading: "moved GOROOT",
@@ -583,14 +585,16 @@ func (t *tester) registerTests() {
}
// sync tests
- t.tests = append(t.tests, distTest{
- name: "sync_cpu",
- heading: "sync -cpu=10",
- fn: func(dt *distTest) error {
- t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
- return nil
- },
- })
+ if goos != "js" { // js doesn't support -cpu=10
+ t.tests = append(t.tests, distTest{
+ name: "sync_cpu",
+ heading: "sync -cpu=10",
+ fn: func(dt *distTest) error {
+ t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
+ return nil
+ },
+ })
+ }
if t.raceDetectorSupported() {
t.tests = append(t.tests, distTest{
@@ -714,7 +718,7 @@ func (t *tester) registerTests() {
// Doc tests only run on builders.
// They find problems approximately never.
- if t.hasBash() && goos != "nacl" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
+ if t.hasBash() && goos != "nacl" && goos != "js" && goos != "android" && !t.iOS() && os.Getenv("GO_BUILDER_NAME") != "" {
t.registerTest("doc_progs", "../doc/progs", "time", "go", "run", "run.go")
t.registerTest("wiki", "../doc/articles/wiki", "./test.bash")
t.registerTest("codewalk", "../doc/codewalk", "time", "./run")
@@ -740,7 +744,7 @@ func (t *tester) registerTests() {
})
}
}
- if goos != "nacl" && goos != "android" && !t.iOS() {
+ if goos != "nacl" && goos != "android" && !t.iOS() && goos != "js" {
t.tests = append(t.tests, distTest{
name: "api",
heading: "API check",
@@ -1318,7 +1322,7 @@ func (t *tester) raceDetectorSupported() bool {
case "linux", "darwin", "freebsd", "windows":
// The race detector doesn't work on Alpine Linux:
// golang.org/issue/14481
- return t.cgoEnabled && goarch == "amd64" && gohostos == goos && !isAlpineLinux()
+ return t.cgoEnabled && (goarch == "amd64" || goarch == "ppc64le") && gohostos == goos && !isAlpineLinux()
}
return false
}
@@ -1335,13 +1339,16 @@ func (t *tester) runFlag(rx string) string {
if t.compileOnly {
return "-run=^$"
}
+ if rx == "" && goos == "js" && goarch == "wasm" {
+ return "-run=^Test" // exclude examples; Issue 25913
+ }
return "-run=" + rx
}
func (t *tester) raceTest(dt *distTest) error {
t.addCmd(dt, "src", t.goTest(), "-race", "-i", "runtime/race", "flag", "os", "os/exec")
t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
- t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace"), "flag", "os", "os/exec", "encoding/gob")
+ t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
// We don't want the following line, because it
// slows down all.bash (by 10 seconds on my laptop).
// The race builder should catch any error here, but doesn't.
diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go
index f1072b5e41..e68e95f3fb 100644
--- a/src/cmd/doc/doc_test.go
+++ b/src/cmd/doc/doc_test.go
@@ -26,7 +26,7 @@ func TestMain(m *testing.M) {
if err != nil {
panic(err)
}
- dirsInit(testdataDir)
+ dirsInit(testdataDir, filepath.Join(testdataDir, "nested"), filepath.Join(testdataDir, "nested", "nested"))
os.Exit(m.Run())
}
@@ -510,6 +510,24 @@ var tests = []test{
"\\)\n+const", // This will appear if the const decl appears twice.
},
},
+ {
+ "non-imported: pkg.sym",
+ []string{"nested.Foo"},
+ []string{"Foo struct"},
+ nil,
+ },
+ {
+ "non-imported: pkg only",
+ []string{"nested"},
+ []string{"Foo struct"},
+ nil,
+ },
+ {
+ "non-imported: pkg sym",
+ []string{"nested", "Foo"},
+ []string{"Foo struct"},
+ nil,
+ },
}
func TestDoc(t *testing.T) {
diff --git a/src/cmd/doc/main.go b/src/cmd/doc/main.go
index 9f947146a4..bf0c7723f8 100644
--- a/src/cmd/doc/main.go
+++ b/src/cmd/doc/main.go
@@ -189,11 +189,16 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo
// Done below.
case 2:
// Package must be findable and importable.
- packagePath, ok := findPackage(arg)
- if !ok {
- return nil, args[0], args[1], false
+ for {
+ packagePath, ok := findNextPackage(arg)
+ if !ok {
+ break
+ }
+ if pkg, err := build.ImportDir(packagePath, build.ImportComment); err == nil {
+ return pkg, arg, args[1], true
+ }
}
- return importDir(packagePath), arg, args[1], true
+ return nil, args[0], args[1], false
}
// Usual case: one argument.
// If it contains slashes, it begins with a package path.
@@ -241,9 +246,15 @@ func parseArgs(args []string) (pkg *build.Package, path, symbol string, more boo
}
// See if we have the basename or tail of a package, as in json for encoding/json
// or ivy/value for robpike.io/ivy/value.
- path, ok := findPackage(arg[0:period])
- if ok {
- return importDir(path), arg[0:period], symbol, true
+ pkgName := arg[:period]
+ for {
+ path, ok := findNextPackage(pkgName)
+ if !ok {
+ break
+ }
+ if pkg, err = build.ImportDir(path, build.ImportComment); err == nil {
+ return pkg, arg[0:period], symbol, true
+ }
}
dirs.Reset() // Next iteration of for loop must scan all the directories again.
}
@@ -338,9 +349,9 @@ func isUpper(name string) bool {
return unicode.IsUpper(ch)
}
-// findPackage returns the full file name path that first matches the
+// findNextPackage returns the next full file name path that matches the
// (perhaps partial) package path pkg. The boolean reports if any match was found.
-func findPackage(pkg string) (string, bool) {
+func findNextPackage(pkg string) (string, bool) {
if pkg == "" || isUpper(pkg) { // Upper case symbol cannot be a package name.
return "", false
}
diff --git a/src/cmd/doc/testdata/nested/ignore.go b/src/cmd/doc/testdata/nested/ignore.go
new file mode 100644
index 0000000000..c497f1b5bc
--- /dev/null
+++ b/src/cmd/doc/testdata/nested/ignore.go
@@ -0,0 +1,4 @@
+// +build ignore
+
+// Ignored package
+package nested
diff --git a/src/cmd/doc/testdata/nested/nested/real.go b/src/cmd/doc/testdata/nested/nested/real.go
new file mode 100644
index 0000000000..1e5546081c
--- /dev/null
+++ b/src/cmd/doc/testdata/nested/nested/real.go
@@ -0,0 +1,4 @@
+package nested
+
+type Foo struct {
+}
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 3494601e69..fd281460b1 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.
+// Code generated by mkalldocs.sh; DO NOT EDIT.
// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.
// Go is a tool for managing Go source code.
@@ -419,6 +419,12 @@
// (gofmt), a fully qualified path (/usr/you/bin/mytool), or a
// command alias, described below.
//
+// To convey to humans and machine tools that code is generated,
+// generated source should have a line early in the file that
+// matches the following regular expression (in Go syntax):
+//
+// ^// Code generated .* DO NOT EDIT\.$
+//
// Note that go generate does not parse the file, so lines that look
// like directives in comments or multiline strings will be treated
// as directives.
@@ -579,7 +585,7 @@
//
// Usage:
//
-// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages]
+// go list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages]
//
// List lists the packages named by the import paths, one per line.
//
@@ -1006,6 +1012,7 @@
// in the standard user cache directory for the current operating system.
// Setting the GOCACHE environment variable overrides this default,
// and running 'go env GOCACHE' prints the current cache directory.
+// You can set the variable to 'off' to disable the cache.
//
// The go command periodically deletes cached data that has not been
// used recently. Running 'go clean -cache' deletes all cached data.
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index f7ac776eb6..896647ae17 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -99,6 +99,7 @@ func init() {
var testGOROOT string
var testCC string
+var testGOCACHE string
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
@@ -175,6 +176,13 @@ func TestMain(m *testing.M) {
}
}
+ out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out)
+ os.Exit(2)
+ }
+ testGOCACHE = strings.TrimSpace(string(out))
+
// As of Sept 2017, MSan is only supported on linux/amd64.
// https://github.com/google/sanitizers/wiki/MemorySanitizer#getting-memorysanitizer
canMSan = canCgo && runtime.GOOS == "linux" && runtime.GOARCH == "amd64"
@@ -198,7 +206,7 @@ func TestMain(m *testing.M) {
}
os.Setenv("HOME", "/test-go-home-does-not-exist")
if os.Getenv("GOCACHE") == "" {
- os.Setenv("GOCACHE", "off") // because $HOME is gone
+ os.Setenv("GOCACHE", testGOCACHE) // because $HOME is gone
}
r := m.Run()
@@ -791,7 +799,6 @@ func TestBuildComplex(t *testing.T) {
tg.run("build", "-x", "-o", os.DevNull, "complex")
if _, err := exec.LookPath("gccgo"); err == nil {
- t.Skip("golang.org/issue/22472")
tg.run("build", "-x", "-o", os.DevNull, "-compiler=gccgo", "complex")
}
}
@@ -1253,14 +1260,14 @@ func TestInternalPackagesInGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal")
- tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrong error message for testdata/testinternal")
+ tg.grepBoth(`testinternal(\/|\\)p\.go\:3\:8\: use of internal package net/http/internal not allowed`, "wrong error message for testdata/testinternal")
}
func TestInternalPackagesOutsideGOROOTAreRespected(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.runFail("build", "-v", "./testdata/testinternal2")
- tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package not allowed`, "wrote error message for testdata/testinternal2")
+ tg.grepBoth(`testinternal2(\/|\\)p\.go\:3\:8\: use of internal package .*internal/w not allowed`, "wrote error message for testdata/testinternal2")
}
func TestRunInternal(t *testing.T) {
@@ -1270,7 +1277,7 @@ func TestRunInternal(t *testing.T) {
tg.setenv("GOPATH", dir)
tg.run("run", filepath.Join(dir, "src/run/good.go"))
tg.runFail("run", filepath.Join(dir, "src/run/bad.go"))
- tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package not allowed`, "unexpected error for run/bad.go")
+ tg.grepStderr(`testdata(\/|\\)src(\/|\\)run(\/|\\)bad\.go\:3\:8\: use of internal package run/subdir/internal/private not allowed`, "unexpected error for run/bad.go")
}
func TestRunPkg(t *testing.T) {
@@ -1975,6 +1982,10 @@ func TestGoListTest(t *testing.T) {
tg.run("list", "-test", "runtime/cgo")
tg.grepStdout(`^runtime/cgo$`, "missing runtime/cgo")
+
+ tg.run("list", "-deps", "-f", "{{if .DepOnly}}{{.ImportPath}}{{end}}", "sort")
+ tg.grepStdout(`^reflect$`, "missing reflect")
+ tg.grepStdoutNot(`^sort`, "unexpected sort")
}
func TestGoListCgo(t *testing.T) {
@@ -3072,7 +3083,6 @@ func TestIssue7573(t *testing.T) {
if _, err := exec.LookPath("gccgo"); err != nil {
t.Skip("skipping because no gccgo compiler found")
}
- t.Skip("golang.org/issue/22472")
tg := testgo(t)
defer tg.cleanup()
@@ -3257,9 +3267,9 @@ func TestGoTestCoverMultiPackage(t *testing.T) {
tg := testgo(t)
defer tg.cleanup()
tg.run("test", "-cover", "./testdata/testcover/...")
- tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1")
- tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2")
- tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3")
+ tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1")
+ tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2")
+ tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3")
}
// issue 24570
@@ -3268,9 +3278,9 @@ func TestGoTestCoverprofileMultiPackage(t *testing.T) {
defer tg.cleanup()
tg.creatingTemp("testdata/cover.out")
tg.run("test", "-coverprofile=testdata/cover.out", "./testdata/testcover/...")
- tg.grepStdout(`\?.*testdata/testcover/pkg1.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1")
- tg.grepStdout(`ok.*testdata/testcover/pkg2.*\d\.\d\d\ds.*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2")
- tg.grepStdout(`ok.*testdata/testcover/pkg3.*\d\.\d\d\ds.*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3")
+ tg.grepStdout(`\?.*testdata/testcover/pkg1.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no test files\]`, "expected [no test files] for pkg1")
+ tg.grepStdout(`ok.*testdata/testcover/pkg2.*(\d\.\d\d\ds|cached).*coverage:.*0\.0% of statements \[no tests to run\]`, "expected [no tests to run] for pkg2")
+ tg.grepStdout(`ok.*testdata/testcover/pkg3.*(\d\.\d\d\ds|cached).*coverage:.*100\.0% of statements`, "expected 100% coverage for pkg3")
if out, err := ioutil.ReadFile("testdata/cover.out"); err != nil {
t.Error(err)
} else {
@@ -5815,6 +5825,11 @@ func TestTestVet(t *testing.T) {
tg.runFail("test", "vetfail/...")
tg.grepStderr(`Printf format %d`, "did not diagnose bad Printf")
tg.grepStdout(`ok\s+vetfail/p2`, "did not run vetfail/p2")
+
+ // Use -a so that we need to recompute the vet-specific export data for
+ // vetfail/p1.
+ tg.run("test", "-a", "vetfail/p2")
+ tg.grepStderrNot(`invalid.*constraint`, "did diagnose bad build constraint in vetxonly mode")
}
func TestTestVetRebuild(t *testing.T) {
diff --git a/src/cmd/go/internal/cache/cache.go b/src/cmd/go/internal/cache/cache.go
index edb58826f1..0cf01550ff 100644
--- a/src/cmd/go/internal/cache/cache.go
+++ b/src/cmd/go/internal/cache/cache.go
@@ -189,6 +189,21 @@ func (c *Cache) get(id ActionID) (Entry, error) {
return Entry{buf, size, time.Unix(0, tm)}, nil
}
+// GetFile looks up the action ID in the cache and returns
+// the name of the corresponding data file.
+func (c *Cache) GetFile(id ActionID) (file string, entry Entry, err error) {
+ entry, err = c.Get(id)
+ if err != nil {
+ return "", Entry{}, err
+ }
+ file = c.OutputFile(entry.OutputID)
+ info, err := os.Stat(file)
+ if err != nil || info.Size() != entry.Size {
+ return "", Entry{}, errMissing
+ }
+ return file, entry, nil
+}
+
// GetBytes looks up the action ID in the cache and returns
// the corresponding output bytes.
// GetBytes should only be used for data that can be expected to fit in memory.
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index 3df5905d02..b7906bb1db 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -103,6 +103,16 @@ func init() {
}
}
+// There is a copy of findGOROOT, isSameDir, and isGOROOT in
+// x/tools/cmd/godoc/goroot.go.
+// Try to keep them in sync for now.
+
+// findGOROOT returns the GOROOT value, using either an explicitly
+// provided environment variable, a GOROOT that contains the current
+// os.Executable value, or else the GOROOT that the binary was built
+// with from runtime.GOROOT().
+//
+// There is a copy of this code in x/tools/cmd/godoc/goroot.go.
func findGOROOT() string {
if env := os.Getenv("GOROOT"); env != "" {
return filepath.Clean(env)
@@ -162,6 +172,8 @@ func isSameDir(dir1, dir2 string) bool {
// It does this by looking for the path/pkg/tool directory,
// which is necessary for useful operation of the cmd/go tool,
// and is not typically present in a GOPATH.
+//
+// There is a copy of this code in x/tools/cmd/godoc/goroot.go.
func isGOROOT(path string) bool {
stat, err := os.Stat(filepath.Join(path, "pkg", "tool"))
if err != nil {
diff --git a/src/cmd/go/internal/dirhash/hash.go b/src/cmd/go/internal/dirhash/hash.go
new file mode 100644
index 0000000000..61d8face56
--- /dev/null
+++ b/src/cmd/go/internal/dirhash/hash.go
@@ -0,0 +1,103 @@
+// Copyright 2018 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 dirhash defines hashes over directory trees.
+package dirhash
+
+import (
+ "archive/zip"
+ "crypto/sha256"
+ "encoding/base64"
+ "errors"
+ "fmt"
+ "io"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+)
+
+var DefaultHash = Hash1
+
+type Hash func(files []string, open func(string) (io.ReadCloser, error)) (string, error)
+
+func Hash1(files []string, open func(string) (io.ReadCloser, error)) (string, error) {
+ h := sha256.New()
+ files = append([]string(nil), files...)
+ sort.Strings(files)
+ for _, file := range files {
+ if strings.Contains(file, "\n") {
+ return "", errors.New("filenames with newlines are not supported")
+ }
+ r, err := open(file)
+ if err != nil {
+ return "", err
+ }
+ hf := sha256.New()
+ _, err = io.Copy(hf, r)
+ r.Close()
+ if err != nil {
+ return "", err
+ }
+ fmt.Fprintf(h, "%x %s\n", hf.Sum(nil), file)
+ }
+ return "h1:" + base64.StdEncoding.EncodeToString(h.Sum(nil)), nil
+}
+
+func HashDir(dir, prefix string, hash Hash) (string, error) {
+ files, err := DirFiles(dir, prefix)
+ if err != nil {
+ return "", err
+ }
+ osOpen := func(name string) (io.ReadCloser, error) {
+ return os.Open(filepath.Join(dir, strings.TrimPrefix(name, prefix)))
+ }
+ return hash(files, osOpen)
+}
+
+func DirFiles(dir, prefix string) ([]string, error) {
+ var files []string
+ dir = filepath.Clean(dir)
+ err := filepath.Walk(dir, func(file string, info os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if info.IsDir() {
+ return nil
+ }
+ rel := file
+ if dir != "." {
+ rel = file[len(dir)+1:]
+ }
+ f := filepath.Join(prefix, rel)
+ files = append(files, filepath.ToSlash(f))
+ return nil
+ })
+ if err != nil {
+ return nil, err
+ }
+ return files, nil
+}
+
+func HashZip(zipfile string, hash Hash) (string, error) {
+ z, err := zip.OpenReader(zipfile)
+ if err != nil {
+ return "", err
+ }
+ defer z.Close()
+ var files []string
+ zfiles := make(map[string]*zip.File)
+ for _, file := range z.File {
+ files = append(files, file.Name)
+ zfiles[file.Name] = file
+ }
+ zipOpen := func(name string) (io.ReadCloser, error) {
+ f := zfiles[name]
+ if f == nil {
+ return nil, fmt.Errorf("file %q not found in zip", name) // should never happen
+ }
+ return f.Open()
+ }
+ return hash(files, zipOpen)
+}
diff --git a/src/cmd/go/internal/dirhash/hash_test.go b/src/cmd/go/internal/dirhash/hash_test.go
new file mode 100644
index 0000000000..ed463c1949
--- /dev/null
+++ b/src/cmd/go/internal/dirhash/hash_test.go
@@ -0,0 +1,135 @@
+// Copyright 2018 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 dirhash
+
+import (
+ "archive/zip"
+ "crypto/sha256"
+ "encoding/base64"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+ "testing"
+)
+
+func h(s string) string {
+ return fmt.Sprintf("%x", sha256.Sum256([]byte(s)))
+}
+
+func htop(k string, s string) string {
+ sum := sha256.Sum256([]byte(s))
+ return k + ":" + base64.StdEncoding.EncodeToString(sum[:])
+}
+
+func TestHash1(t *testing.T) {
+ files := []string{"xyz", "abc"}
+ open := func(name string) (io.ReadCloser, error) {
+ return ioutil.NopCloser(strings.NewReader("data for " + name)), nil
+ }
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "abc", h("data for xyz"), "xyz"))
+ out, err := Hash1(files, open)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if out != want {
+ t.Errorf("Hash1(...) = %s, want %s", out, want)
+ }
+
+ _, err = Hash1([]string{"xyz", "a\nbc"}, open)
+ if err == nil {
+ t.Error("Hash1: expected error on newline in filenames")
+ }
+}
+
+func TestHashDir(t *testing.T) {
+ dir, err := ioutil.TempDir("", "dirhash-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "xyz"), []byte("data for xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("data for abc"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "prefix/abc", h("data for xyz"), "prefix/xyz"))
+ out, err := HashDir(dir, "prefix", Hash1)
+ if err != nil {
+ t.Fatalf("HashDir: %v", err)
+ }
+ if out != want {
+ t.Errorf("HashDir(...) = %s, want %s", out, want)
+ }
+}
+
+func TestHashZip(t *testing.T) {
+ f, err := ioutil.TempFile("", "dirhash-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+
+ z := zip.NewWriter(f)
+ w, err := z.Create("prefix/xyz")
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Write([]byte("data for xyz"))
+ w, err = z.Create("prefix/abc")
+ if err != nil {
+ t.Fatal(err)
+ }
+ w.Write([]byte("data for abc"))
+ if err := z.Close(); err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+
+ want := htop("h1", fmt.Sprintf("%s %s\n%s %s\n", h("data for abc"), "prefix/abc", h("data for xyz"), "prefix/xyz"))
+ out, err := HashZip(f.Name(), Hash1)
+ if err != nil {
+ t.Fatalf("HashDir: %v", err)
+ }
+ if out != want {
+ t.Errorf("HashDir(...) = %s, want %s", out, want)
+ }
+}
+
+func TestDirFiles(t *testing.T) {
+ dir, err := ioutil.TempDir("", "dirfiles-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ if err := ioutil.WriteFile(filepath.Join(dir, "xyz"), []byte("data for xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "abc"), []byte("data for abc"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Mkdir(filepath.Join(dir, "subdir"), 0777); err != nil {
+ t.Fatal(err)
+ }
+ if err := ioutil.WriteFile(filepath.Join(dir, "subdir", "xyz"), []byte("data for subdir xyz"), 0666); err != nil {
+ t.Fatal(err)
+ }
+ prefix := "foo/bar@v2.3.4"
+ out, err := DirFiles(dir, prefix)
+ if err != nil {
+ t.Fatalf("DirFiles: %v", err)
+ }
+ for _, file := range out {
+ if !strings.HasPrefix(file, prefix) {
+ t.Errorf("Dir file = %s, want prefix %s", file, prefix)
+ }
+ }
+}
diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go
index f682c3a789..bd66a98f21 100644
--- a/src/cmd/go/internal/envcmd/env.go
+++ b/src/cmd/go/internal/envcmd/env.go
@@ -16,6 +16,7 @@ import (
"cmd/go/internal/cache"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/vgo"
"cmd/go/internal/work"
)
@@ -56,6 +57,7 @@ func MkEnv() []cfg.EnvVar {
{Name: "GOHOSTOS", Value: runtime.GOOS},
{Name: "GOOS", Value: cfg.Goos},
{Name: "GOPATH", Value: cfg.BuildContext.GOPATH},
+ {Name: "GOPROXY", Value: os.Getenv("GOPROXY")},
{Name: "GORACE", Value: os.Getenv("GORACE")},
{Name: "GOROOT", Value: cfg.GOROOT},
{Name: "GOTMPDIR", Value: os.Getenv("GOTMPDIR")},
@@ -131,6 +133,7 @@ func ExtraEnvVars() []cfg.EnvVar {
{Name: "CGO_LDFLAGS", Value: strings.Join(ldflags, " ")},
{Name: "PKG_CONFIG", Value: b.PkgconfigCmd()},
{Name: "GOGCCFLAGS", Value: strings.Join(cmd[3:], " ")},
+ {Name: "VGOMODROOT", Value: vgo.ModRoot},
}
}
diff --git a/src/cmd/go/internal/fix/fix.go b/src/cmd/go/internal/fix/fix.go
index 99c7ca51ac..56f88329ab 100644
--- a/src/cmd/go/internal/fix/fix.go
+++ b/src/cmd/go/internal/fix/fix.go
@@ -10,6 +10,9 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
+ "cmd/go/internal/vgo"
+ "fmt"
+ "os"
)
var CmdFix = &base.Command{
@@ -29,7 +32,15 @@ See also: go fmt, go vet.
}
func runFix(cmd *base.Command, args []string) {
+ printed := false
for _, pkg := range load.Packages(args) {
+ if vgo.Enabled() && !pkg.Module.Top {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "vgo: not fixing packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
// Use pkg.gofiles instead of pkg.Dir so that
// the command only applies to this package,
// not to packages in subdirectories.
diff --git a/src/cmd/go/internal/fmtcmd/fmt.go b/src/cmd/go/internal/fmtcmd/fmt.go
index eb96823fa6..c3a90d069c 100644
--- a/src/cmd/go/internal/fmtcmd/fmt.go
+++ b/src/cmd/go/internal/fmtcmd/fmt.go
@@ -6,6 +6,7 @@
package fmtcmd
import (
+ "fmt"
"os"
"path/filepath"
"runtime"
@@ -16,6 +17,7 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
+ "cmd/go/internal/vgo"
)
func init() {
@@ -43,6 +45,7 @@ See also: go fix, go vet.
}
func runFmt(cmd *base.Command, args []string) {
+ printed := false
gofmt := gofmtPath()
procs := runtime.GOMAXPROCS(0)
var wg sync.WaitGroup
@@ -57,6 +60,13 @@ func runFmt(cmd *base.Command, args []string) {
}()
}
for _, pkg := range load.PackagesAndErrors(args) {
+ if vgo.Enabled() && !pkg.Module.Top {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "vgo: not formatting packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
if pkg.Error != nil {
if strings.HasPrefix(pkg.Error.Err, "build constraints exclude all Go files") {
// Skip this error, as we will format
diff --git a/src/cmd/go/internal/generate/generate.go b/src/cmd/go/internal/generate/generate.go
index 441f91aea8..365427d442 100644
--- a/src/cmd/go/internal/generate/generate.go
+++ b/src/cmd/go/internal/generate/generate.go
@@ -21,6 +21,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/vgo"
"cmd/go/internal/work"
)
@@ -47,6 +48,12 @@ that can be run locally. It must either be in the shell path
(gofmt), a fully qualified path (/usr/you/bin/mytool), or a
command alias, described below.
+To convey to humans and machine tools that code is generated,
+generated source should have a line early in the file that
+matches the following regular expression (in Go syntax):
+
+ ^// Code generated .* DO NOT EDIT\.$
+
Note that go generate does not parse the file, so lines that look
like directives in comments or multiline strings will be treated
as directives.
@@ -152,7 +159,16 @@ func runGenerate(cmd *base.Command, args []string) {
}
}
// Even if the arguments are .go files, this loop suffices.
+ printed := false
for _, pkg := range load.Packages(args) {
+ if vgo.Enabled() && !pkg.Module.Top {
+ if !printed {
+ fmt.Fprintf(os.Stderr, "vgo: not generating in packages in dependency modules\n")
+ printed = true
+ }
+ continue
+ }
+
pkgName := pkg.Name
for _, file := range pkg.InternalGoFiles() {
diff --git a/src/cmd/go/internal/get/get.go b/src/cmd/go/internal/get/get.go
index ffa15c5ba4..6eabc4eabb 100644
--- a/src/cmd/go/internal/get/get.go
+++ b/src/cmd/go/internal/get/get.go
@@ -16,7 +16,9 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/search"
"cmd/go/internal/str"
+ "cmd/go/internal/vgo"
"cmd/go/internal/web"
"cmd/go/internal/work"
)
@@ -90,6 +92,10 @@ func init() {
}
func runGet(cmd *base.Command, args []string) {
+ if vgo.Enabled() {
+ base.Fatalf("go get: vgo not implemented")
+ }
+
work.BuildInit()
if *getF && !*getU {
@@ -170,7 +176,7 @@ func runGet(cmd *base.Command, args []string) {
// in the hope that we can figure out the repository from the
// initial ...-free prefix.
func downloadPaths(args []string) []string {
- args = load.ImportPathsNoDotExpansion(args)
+ args = load.ImportPathsForGoGet(args)
var out []string
for _, a := range args {
if strings.Contains(a, "...") {
@@ -179,9 +185,9 @@ func downloadPaths(args []string) []string {
// warnings. They will be printed by the
// eventual call to importPaths instead.
if build.IsLocalImport(a) {
- expand = load.MatchPackagesInFS(a)
+ expand = search.MatchPackagesInFS(a)
} else {
- expand = load.MatchPackages(a)
+ expand = search.MatchPackages(a)
}
if len(expand) > 0 {
out = append(out, expand...)
@@ -271,9 +277,9 @@ func download(arg string, parent *load.Package, stk *load.ImportStack, mode int)
// for p has been replaced in the package cache.
if wildcardOkay && strings.Contains(arg, "...") {
if build.IsLocalImport(arg) {
- args = load.MatchPackagesInFS(arg)
+ args = search.MatchPackagesInFS(arg)
} else {
- args = load.MatchPackages(arg)
+ args = search.MatchPackages(arg)
}
isWildcard = true
}
diff --git a/src/cmd/go/internal/help/help.go b/src/cmd/go/internal/help/help.go
index b4c5217f83..c79bf8bebb 100644
--- a/src/cmd/go/internal/help/help.go
+++ b/src/cmd/go/internal/help/help.go
@@ -39,7 +39,7 @@ func Help(args []string) {
fmt.Println("// Use of this source code is governed by a BSD-style")
fmt.Println("// license that can be found in the LICENSE file.")
fmt.Println()
- fmt.Println("// DO NOT EDIT THIS FILE. GENERATED BY mkalldocs.sh.")
+ fmt.Println("// Code generated by mkalldocs.sh; DO NOT EDIT.")
fmt.Println("// Edit the documentation in other files and rerun mkalldocs.sh to generate this one.")
fmt.Println()
buf := new(bytes.Buffer)
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index a90d19e976..ce19796558 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -658,6 +658,7 @@ The default location for cache data is a subdirectory named go-build
in the standard user cache directory for the current operating system.
Setting the GOCACHE environment variable overrides this default,
and running 'go env GOCACHE' prints the current cache directory.
+You can set the variable to 'off' to disable the cache.
The go command periodically deletes cached data that has not been
used recently. Running 'go clean -cache' deletes all cached data.
diff --git a/src/cmd/go/internal/imports/build.go b/src/cmd/go/internal/imports/build.go
new file mode 100644
index 0000000000..5597870a02
--- /dev/null
+++ b/src/cmd/go/internal/imports/build.go
@@ -0,0 +1,211 @@
+// Copyright 2018 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.
+
+// Copied from Go distribution src/go/build/build.go, syslist.go
+
+package imports
+
+import (
+ "bytes"
+ "strings"
+ "unicode"
+)
+
+var slashslash = []byte("//")
+
+// ShouldBuild reports whether it is okay to use this file,
+// The rule is that in the file's leading run of // comments
+// and blank lines, which must be followed by a blank line
+// (to avoid including a Go package clause doc comment),
+// lines beginning with '// +build' are taken as build directives.
+//
+// The file is accepted only if each such line lists something
+// matching the file. For example:
+//
+// // +build windows linux
+//
+// marks the file as applicable only on Windows and Linux.
+//
+// If tags["*"] is true, then ShouldBuild will consider every
+// build tag except "ignore" to be both true and false for
+// the purpose of satisfying build tags, in order to estimate
+// (conservatively) whether a file could ever possibly be used
+// in any build.
+//
+func ShouldBuild(content []byte, tags map[string]bool) bool {
+ // Pass 1. Identify leading run of // comments and blank lines,
+ // which must be followed by a blank line.
+ end := 0
+ p := content
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if len(line) == 0 { // Blank line
+ end = len(content) - len(p)
+ continue
+ }
+ if !bytes.HasPrefix(line, slashslash) { // Not comment line
+ break
+ }
+ }
+ content = content[:end]
+
+ // Pass 2. Process each line in the run.
+ p = content
+ allok := true
+ for len(p) > 0 {
+ line := p
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, p = line[:i], p[i+1:]
+ } else {
+ p = p[len(p):]
+ }
+ line = bytes.TrimSpace(line)
+ if !bytes.HasPrefix(line, slashslash) {
+ continue
+ }
+ line = bytes.TrimSpace(line[len(slashslash):])
+ if len(line) > 0 && line[0] == '+' {
+ // Looks like a comment +line.
+ f := strings.Fields(string(line))
+ if f[0] == "+build" {
+ ok := false
+ for _, tok := range f[1:] {
+ if matchTags(tok, tags) {
+ ok = true
+ }
+ }
+ if !ok {
+ allok = false
+ }
+ }
+ }
+ }
+
+ return allok
+}
+
+// matchTags reports whether the name is one of:
+//
+// tag (if tags[tag] is true)
+// !tag (if tags[tag] is false)
+// a comma-separated list of any of these
+//
+func matchTags(name string, tags map[string]bool) bool {
+ if name == "" {
+ return false
+ }
+ if i := strings.Index(name, ","); i >= 0 {
+ // comma-separated list
+ ok1 := matchTags(name[:i], tags)
+ ok2 := matchTags(name[i+1:], tags)
+ return ok1 && ok2
+ }
+ if strings.HasPrefix(name, "!!") { // bad syntax, reject always
+ return false
+ }
+ if strings.HasPrefix(name, "!") { // negation
+ return len(name) > 1 && matchTag(name[1:], tags, false)
+ }
+ return matchTag(name, tags, true)
+}
+
+// matchTag reports whether the tag name is valid and satisfied by tags[name]==want.
+func matchTag(name string, tags map[string]bool, want bool) bool {
+ // Tags must be letters, digits, underscores or dots.
+ // Unlike in Go identifiers, all digits are fine (e.g., "386").
+ for _, c := range name {
+ if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
+ return false
+ }
+ }
+
+ if tags["*"] && name != "" && name != "ignore" {
+ // Special case for gathering all possible imports:
+ // if we put * in the tags map then all tags
+ // except "ignore" are considered both present and not
+ // (so we return true no matter how 'want' is set).
+ return true
+ }
+
+ have := tags[name]
+ if name == "linux" {
+ have = have || tags["android"]
+ }
+ return have == want
+}
+
+// MatchFile returns false if the name contains a $GOOS or $GOARCH
+// suffix which does not match the current system.
+// The recognized name formats are:
+//
+// name_$(GOOS).*
+// name_$(GOARCH).*
+// name_$(GOOS)_$(GOARCH).*
+// name_$(GOOS)_test.*
+// name_$(GOARCH)_test.*
+// name_$(GOOS)_$(GOARCH)_test.*
+//
+// An exception: if GOOS=android, then files with GOOS=linux are also matched.
+//
+// If tags["*"] is true, then MatchFile will consider all possible
+// GOOS and GOARCH to be available and will consequently
+// always return true.
+func MatchFile(name string, tags map[string]bool) bool {
+ if tags["*"] {
+ return true
+ }
+ 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
+ // systems, such as android, to arrive without breaking existing code with
+ // innocuous source code in "android.go". The easiest fix: cut everything
+ // in the name before the initial _.
+ i := strings.Index(name, "_")
+ if i < 0 {
+ return true
+ }
+ name = name[i:] // ignore everything before first _
+
+ l := strings.Split(name, "_")
+ if n := len(l); n > 0 && l[n-1] == "test" {
+ l = l[:n-1]
+ }
+ n := len(l)
+ if n >= 2 && knownOS[l[n-2]] && knownArch[l[n-1]] {
+ return tags[l[n-2]] && tags[l[n-1]]
+ }
+ if n >= 1 && knownOS[l[n-1]] {
+ return tags[l[n-1]]
+ }
+ if n >= 1 && knownArch[l[n-1]] {
+ return tags[l[n-1]]
+ }
+ return true
+}
+
+var knownOS = make(map[string]bool)
+var knownArch = make(map[string]bool)
+
+func init() {
+ for _, v := range strings.Fields(goosList) {
+ knownOS[v] = true
+ }
+ for _, v := range strings.Fields(goarchList) {
+ knownArch[v] = true
+ }
+}
+
+const goosList = "android darwin dragonfly freebsd js linux nacl netbsd openbsd plan9 solaris windows zos "
+const goarchList = "386 amd64 amd64p32 arm armbe arm64 arm64be ppc64 ppc64le mips mipsle mips64 mips64le mips64p32 mips64p32le ppc riscv riscv64 s390 s390x sparc sparc64 wasm "
diff --git a/src/cmd/go/internal/imports/read.go b/src/cmd/go/internal/imports/read.go
new file mode 100644
index 0000000000..58c2abdc29
--- /dev/null
+++ b/src/cmd/go/internal/imports/read.go
@@ -0,0 +1,249 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from Go distribution src/go/build/read.go.
+
+package imports
+
+import (
+ "bufio"
+ "errors"
+ "io"
+ "unicode/utf8"
+)
+
+type importReader struct {
+ b *bufio.Reader
+ buf []byte
+ peek byte
+ err error
+ eof bool
+ nerr int
+}
+
+func isIdent(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '_' || c >= utf8.RuneSelf
+}
+
+var (
+ errSyntax = errors.New("syntax error")
+ errNUL = errors.New("unexpected NUL in input")
+)
+
+// syntaxError records a syntax error, but only if an I/O error has not already been recorded.
+func (r *importReader) syntaxError() {
+ if r.err == nil {
+ r.err = errSyntax
+ }
+}
+
+// readByte reads the next byte from the input, saves it in buf, and returns it.
+// If an error occurs, readByte records the error in r.err and returns 0.
+func (r *importReader) readByte() byte {
+ c, err := r.b.ReadByte()
+ if err == nil {
+ r.buf = append(r.buf, c)
+ if c == 0 {
+ err = errNUL
+ }
+ }
+ if err != nil {
+ if err == io.EOF {
+ r.eof = true
+ } else if r.err == nil {
+ r.err = err
+ }
+ c = 0
+ }
+ return c
+}
+
+// peekByte returns the next byte from the input reader but does not advance beyond it.
+// If skipSpace is set, peekByte skips leading spaces and comments.
+func (r *importReader) peekByte(skipSpace bool) byte {
+ if r.err != nil {
+ if r.nerr++; r.nerr > 10000 {
+ panic("go/build: import reader looping")
+ }
+ return 0
+ }
+
+ // Use r.peek as first input byte.
+ // Don't just return r.peek here: it might have been left by peekByte(false)
+ // and this might be peekByte(true).
+ c := r.peek
+ if c == 0 {
+ c = r.readByte()
+ }
+ for r.err == nil && !r.eof {
+ if skipSpace {
+ // For the purposes of this reader, semicolons are never necessary to
+ // understand the input and are treated as spaces.
+ switch c {
+ case ' ', '\f', '\t', '\r', '\n', ';':
+ c = r.readByte()
+ continue
+
+ case '/':
+ c = r.readByte()
+ if c == '/' {
+ for c != '\n' && r.err == nil && !r.eof {
+ c = r.readByte()
+ }
+ } else if c == '*' {
+ var c1 byte
+ for (c != '*' || c1 != '/') && r.err == nil {
+ if r.eof {
+ r.syntaxError()
+ }
+ c, c1 = c1, r.readByte()
+ }
+ } else {
+ r.syntaxError()
+ }
+ c = r.readByte()
+ continue
+ }
+ }
+ break
+ }
+ r.peek = c
+ return r.peek
+}
+
+// nextByte is like peekByte but advances beyond the returned byte.
+func (r *importReader) nextByte(skipSpace bool) byte {
+ c := r.peekByte(skipSpace)
+ r.peek = 0
+ return c
+}
+
+// readKeyword reads the given keyword from the input.
+// If the keyword is not present, readKeyword records a syntax error.
+func (r *importReader) readKeyword(kw string) {
+ r.peekByte(true)
+ for i := 0; i < len(kw); i++ {
+ if r.nextByte(false) != kw[i] {
+ r.syntaxError()
+ return
+ }
+ }
+ if isIdent(r.peekByte(false)) {
+ r.syntaxError()
+ }
+}
+
+// readIdent reads an identifier from the input.
+// If an identifier is not present, readIdent records a syntax error.
+func (r *importReader) readIdent() {
+ c := r.peekByte(true)
+ if !isIdent(c) {
+ r.syntaxError()
+ return
+ }
+ for isIdent(r.peekByte(false)) {
+ r.peek = 0
+ }
+}
+
+// readString reads a quoted string literal from the input.
+// If an identifier is not present, readString records a syntax error.
+func (r *importReader) readString(save *[]string) {
+ switch r.nextByte(true) {
+ case '`':
+ start := len(r.buf) - 1
+ for r.err == nil {
+ if r.nextByte(false) == '`' {
+ if save != nil {
+ *save = append(*save, string(r.buf[start:]))
+ }
+ break
+ }
+ if r.eof {
+ r.syntaxError()
+ }
+ }
+ case '"':
+ start := len(r.buf) - 1
+ for r.err == nil {
+ c := r.nextByte(false)
+ if c == '"' {
+ if save != nil {
+ *save = append(*save, string(r.buf[start:]))
+ }
+ break
+ }
+ if r.eof || c == '\n' {
+ r.syntaxError()
+ }
+ if c == '\\' {
+ r.nextByte(false)
+ }
+ }
+ default:
+ r.syntaxError()
+ }
+}
+
+// readImport reads an import clause - optional identifier followed by quoted string -
+// from the input.
+func (r *importReader) readImport(imports *[]string) {
+ c := r.peekByte(true)
+ if c == '.' {
+ r.peek = 0
+ } else if isIdent(c) {
+ r.readIdent()
+ }
+ r.readString(imports)
+}
+
+// ReadComments is like ioutil.ReadAll, except that it only reads the leading
+// block of comments in the file.
+func ReadComments(f io.Reader) ([]byte, error) {
+ r := &importReader{b: bufio.NewReader(f)}
+ r.peekByte(true)
+ if r.err == nil && !r.eof {
+ // Didn't reach EOF, so must have found a non-space byte. Remove it.
+ r.buf = r.buf[:len(r.buf)-1]
+ }
+ return r.buf, r.err
+}
+
+// ReadImports is like ioutil.ReadAll, except that it expects a Go file as input
+// and stops reading the input once the imports have completed.
+func ReadImports(f io.Reader, reportSyntaxError bool, imports *[]string) ([]byte, error) {
+ r := &importReader{b: bufio.NewReader(f)}
+
+ r.readKeyword("package")
+ r.readIdent()
+ for r.peekByte(true) == 'i' {
+ r.readKeyword("import")
+ if r.peekByte(true) == '(' {
+ r.nextByte(false)
+ for r.peekByte(true) != ')' && r.err == nil {
+ r.readImport(imports)
+ }
+ r.nextByte(false)
+ } else {
+ r.readImport(imports)
+ }
+ }
+
+ // If we stopped successfully before EOF, we read a byte that told us we were done.
+ // Return all but that last byte, which would cause a syntax error if we let it through.
+ if r.err == nil && !r.eof {
+ return r.buf[:len(r.buf)-1], nil
+ }
+
+ // If we stopped for a syntax error, consume the whole file so that
+ // we are sure we don't change the errors that go/parser returns.
+ if r.err == errSyntax && !reportSyntaxError {
+ r.err = nil
+ for r.err == nil && !r.eof {
+ r.readByte()
+ }
+ }
+
+ return r.buf, r.err
+}
diff --git a/src/cmd/go/internal/imports/read_test.go b/src/cmd/go/internal/imports/read_test.go
new file mode 100644
index 0000000000..6ea356f1ff
--- /dev/null
+++ b/src/cmd/go/internal/imports/read_test.go
@@ -0,0 +1,228 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Copied from Go distribution src/go/build/read.go.
+
+package imports
+
+import (
+ "io"
+ "strings"
+ "testing"
+)
+
+const quote = "`"
+
+type readTest struct {
+ // Test input contains ℙ where readImports should stop.
+ in string
+ err string
+}
+
+var readImportsTests = []readTest{
+ {
+ `package p`,
+ "",
+ },
+ {
+ `package p; import "x"`,
+ "",
+ },
+ {
+ `package p; import . "x"`,
+ "",
+ },
+ {
+ `package p; import "x";ℙvar x = 1`,
+ "",
+ },
+ {
+ `package p
+
+ // comment
+
+ import "x"
+ import _ "x"
+ import a "x"
+
+ /* comment */
+
+ import (
+ "x" /* comment */
+ _ "x"
+ a "x" // comment
+ ` + quote + `x` + quote + `
+ _ /*comment*/ ` + quote + `x` + quote + `
+ a ` + quote + `x` + quote + `
+ )
+ import (
+ )
+ import ()
+ import()import()import()
+ import();import();import()
+
+ ℙvar x = 1
+ `,
+ "",
+ },
+}
+
+var readCommentsTests = []readTest{
+ {
+ `ℙpackage p`,
+ "",
+ },
+ {
+ `ℙpackage p; import "x"`,
+ "",
+ },
+ {
+ `ℙpackage p; import . "x"`,
+ "",
+ },
+ {
+ `// foo
+
+ /* bar */
+
+ /* quux */ // baz
+
+ /*/ zot */
+
+ // asdf
+ ℙHello, world`,
+ "",
+ },
+}
+
+func testRead(t *testing.T, tests []readTest, read func(io.Reader) ([]byte, error)) {
+ for i, tt := range tests {
+ var in, testOut string
+ j := strings.Index(tt.in, "ℙ")
+ if j < 0 {
+ in = tt.in
+ testOut = tt.in
+ } else {
+ in = tt.in[:j] + tt.in[j+len("ℙ"):]
+ testOut = tt.in[:j]
+ }
+ r := strings.NewReader(in)
+ buf, err := read(r)
+ if err != nil {
+ if tt.err == "" {
+ t.Errorf("#%d: err=%q, expected success (%q)", i, err, string(buf))
+ continue
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Errorf("#%d: err=%q, expected %q", i, err, tt.err)
+ continue
+ }
+ continue
+ }
+ if err == nil && tt.err != "" {
+ t.Errorf("#%d: success, expected %q", i, tt.err)
+ continue
+ }
+
+ out := string(buf)
+ if out != testOut {
+ t.Errorf("#%d: wrong output:\nhave %q\nwant %q\n", i, out, testOut)
+ }
+ }
+}
+
+func TestReadImports(t *testing.T) {
+ testRead(t, readImportsTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
+}
+
+func TestReadComments(t *testing.T) {
+ testRead(t, readCommentsTests, ReadComments)
+}
+
+var readFailuresTests = []readTest{
+ {
+ `package`,
+ "syntax error",
+ },
+ {
+ "package p\n\x00\nimport `math`\n",
+ "unexpected NUL in input",
+ },
+ {
+ `package p; import`,
+ "syntax error",
+ },
+ {
+ `package p; import "`,
+ "syntax error",
+ },
+ {
+ "package p; import ` \n\n",
+ "syntax error",
+ },
+ {
+ `package p; import "x`,
+ "syntax error",
+ },
+ {
+ `package p; import _`,
+ "syntax error",
+ },
+ {
+ `package p; import _ "`,
+ "syntax error",
+ },
+ {
+ `package p; import _ "x`,
+ "syntax error",
+ },
+ {
+ `package p; import .`,
+ "syntax error",
+ },
+ {
+ `package p; import . "`,
+ "syntax error",
+ },
+ {
+ `package p; import . "x`,
+ "syntax error",
+ },
+ {
+ `package p; import (`,
+ "syntax error",
+ },
+ {
+ `package p; import ("`,
+ "syntax error",
+ },
+ {
+ `package p; import ("x`,
+ "syntax error",
+ },
+ {
+ `package p; import ("x"`,
+ "syntax error",
+ },
+}
+
+func TestReadFailures(t *testing.T) {
+ // Errors should be reported (true arg to readImports).
+ testRead(t, readFailuresTests, func(r io.Reader) ([]byte, error) { return ReadImports(r, true, nil) })
+}
+
+func TestReadFailuresIgnored(t *testing.T) {
+ // Syntax errors should not be reported (false arg to readImports).
+ // Instead, entire file should be the output and no error.
+ // Convert tests not to return syntax errors.
+ tests := make([]readTest, len(readFailuresTests))
+ copy(tests, readFailuresTests)
+ for i := range tests {
+ tt := &tests[i]
+ if !strings.Contains(tt.err, "NUL") {
+ tt.err = ""
+ }
+ }
+ testRead(t, tests, func(r io.Reader) ([]byte, error) { return ReadImports(r, false, nil) })
+}
diff --git a/src/cmd/go/internal/imports/scan.go b/src/cmd/go/internal/imports/scan.go
new file mode 100644
index 0000000000..095bb64a8d
--- /dev/null
+++ b/src/cmd/go/internal/imports/scan.go
@@ -0,0 +1,82 @@
+// Copyright 2018 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 imports
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+)
+
+func ScanDir(dir string, tags map[string]bool) ([]string, []string, error) {
+ infos, err := ioutil.ReadDir(dir)
+ if err != nil {
+ return nil, nil, err
+ }
+ var files []string
+ for _, info := range infos {
+ name := info.Name()
+ if info.Mode().IsRegular() && !strings.HasPrefix(name, "_") && strings.HasSuffix(name, ".go") && MatchFile(name, tags) {
+ files = append(files, filepath.Join(dir, name))
+ }
+ }
+ return scanFiles(files, tags, false)
+}
+
+func ScanFiles(files []string, tags map[string]bool) ([]string, []string, error) {
+ return scanFiles(files, tags, true)
+}
+
+func scanFiles(files []string, tags map[string]bool, explicitFiles bool) ([]string, []string, error) {
+ imports := make(map[string]bool)
+ testImports := make(map[string]bool)
+ numFiles := 0
+ for _, name := range files {
+ r, err := os.Open(name)
+ if err != nil {
+ return nil, nil, err
+ }
+ var list []string
+ data, err := ReadImports(r, false, &list)
+ r.Close()
+ if err != nil {
+ return nil, nil, fmt.Errorf("reading %s: %v", name, err)
+ }
+ if !explicitFiles && !ShouldBuild(data, tags) {
+ continue
+ }
+ numFiles++
+ m := imports
+ if strings.HasSuffix(name, "_test.go") {
+ m = testImports
+ }
+ for _, p := range list {
+ q, err := strconv.Unquote(p)
+ if err != nil {
+ continue
+ }
+ m[q] = true
+ }
+ }
+ if numFiles == 0 {
+ return nil, nil, ErrNoGo
+ }
+ return keys(imports), keys(testImports), nil
+}
+
+var ErrNoGo = fmt.Errorf("no Go source files")
+
+func keys(m map[string]bool) []string {
+ var list []string
+ for k := range m {
+ list = append(list, k)
+ }
+ sort.Strings(list)
+ return list
+}
diff --git a/src/cmd/go/internal/imports/scan_test.go b/src/cmd/go/internal/imports/scan_test.go
new file mode 100644
index 0000000000..6a2ff62ba7
--- /dev/null
+++ b/src/cmd/go/internal/imports/scan_test.go
@@ -0,0 +1,67 @@
+// Copyright 2018 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 imports
+
+import (
+ "internal/testenv"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "testing"
+)
+
+func TestScan(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ imports, testImports, err := ScanDir(filepath.Join(runtime.GOROOT(), "src/encoding/json"), Tags())
+ if err != nil {
+ t.Fatal(err)
+ }
+ foundBase64 := false
+ for _, p := range imports {
+ if p == "encoding/base64" {
+ foundBase64 = true
+ }
+ if p == "encoding/binary" {
+ // A dependency but not an import
+ t.Errorf("json reported as importing encoding/binary but does not")
+ }
+ if p == "net/http" {
+ // A test import but not an import
+ t.Errorf("json reported as importing encoding/binary but does not")
+ }
+ }
+ if !foundBase64 {
+ t.Errorf("json missing import encoding/base64 (%q)", imports)
+ }
+
+ foundHTTP := false
+ for _, p := range testImports {
+ if p == "net/http" {
+ foundHTTP = true
+ }
+ if p == "unicode/utf16" {
+ // A package import but not a test import
+ t.Errorf("json reported as test-importing unicode/utf16 but does not")
+ }
+ }
+ if !foundHTTP {
+ t.Errorf("json missing test import net/http (%q)", testImports)
+ }
+}
+
+func TestScanStar(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ imports, _, err := ScanDir("testdata/import1", map[string]bool{"*": true})
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ want := []string{"import1", "import2", "import3", "import4"}
+ if !reflect.DeepEqual(imports, want) {
+ t.Errorf("ScanDir testdata/import1:\nhave %v\nwant %v", imports, want)
+ }
+}
diff --git a/src/cmd/go/internal/imports/tags.go b/src/cmd/go/internal/imports/tags.go
new file mode 100644
index 0000000000..ba0ca94535
--- /dev/null
+++ b/src/cmd/go/internal/imports/tags.go
@@ -0,0 +1,35 @@
+// Copyright 2018 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 imports
+
+import "cmd/go/internal/cfg"
+
+var tags map[string]bool
+
+func Tags() map[string]bool {
+ if tags == nil {
+ tags = loadTags()
+ }
+ return tags
+}
+
+func loadTags() map[string]bool {
+ tags := map[string]bool{
+ cfg.BuildContext.GOOS: true,
+ cfg.BuildContext.GOARCH: true,
+ cfg.BuildContext.Compiler: true,
+ }
+ if cfg.BuildContext.CgoEnabled {
+ tags["cgo"] = true
+ }
+ // TODO: Should read these out of GOROOT source code?
+ for _, tag := range cfg.BuildContext.BuildTags {
+ tags[tag] = true
+ }
+ for _, tag := range cfg.BuildContext.ReleaseTags {
+ tags[tag] = true
+ }
+ return tags
+}
diff --git a/src/cmd/go/internal/imports/testdata/import1/x.go b/src/cmd/go/internal/imports/testdata/import1/x.go
new file mode 100644
index 0000000000..98f9191053
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/import1/x.go
@@ -0,0 +1,3 @@
+package x
+
+import "import1"
diff --git a/src/cmd/go/internal/imports/testdata/import1/x1.go b/src/cmd/go/internal/imports/testdata/import1/x1.go
new file mode 100644
index 0000000000..6a9594aed0
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/import1/x1.go
@@ -0,0 +1,9 @@
+// +build blahblh
+// +build linux
+// +build !linux
+// +build windows
+// +build darwin
+
+package x
+
+import "import4"
diff --git a/src/cmd/go/internal/imports/testdata/import1/x_darwin.go b/src/cmd/go/internal/imports/testdata/import1/x_darwin.go
new file mode 100644
index 0000000000..a0c3fdd21b
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/import1/x_darwin.go
@@ -0,0 +1,3 @@
+package xxxx
+
+import "import3"
diff --git a/src/cmd/go/internal/imports/testdata/import1/x_windows.go b/src/cmd/go/internal/imports/testdata/import1/x_windows.go
new file mode 100644
index 0000000000..63c508248f
--- /dev/null
+++ b/src/cmd/go/internal/imports/testdata/import1/x_windows.go
@@ -0,0 +1,3 @@
+package x
+
+import "import2"
diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go
index 7261d24839..218999c7e8 100644
--- a/src/cmd/go/internal/list/list.go
+++ b/src/cmd/go/internal/list/list.go
@@ -23,7 +23,7 @@ import (
)
var CmdList = &base.Command{
- UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-list] [-test] [build flags] [packages]",
+ UsageLine: "list [-cgo] [-deps] [-e] [-export] [-f format] [-json] [-test] [build flags] [packages]",
Short: "list packages",
Long: `
List lists the packages named by the import paths, one per line.
@@ -335,6 +335,7 @@ func runList(cmd *base.Command, args []string) {
// Show vendor-expanded paths in listing
p.TestImports = p.Resolve(p.TestImports)
p.XTestImports = p.Resolve(p.XTestImports)
+ p.DepOnly = !cmdline[p]
}
if *listTest {
diff --git a/src/cmd/go/internal/load/path.go b/src/cmd/go/internal/load/path.go
index 45a9e7b242..0211b284a4 100644
--- a/src/cmd/go/internal/load/path.go
+++ b/src/cmd/go/internal/load/path.go
@@ -32,22 +32,6 @@ func hasSubdir(root, dir string) (rel string, ok bool) {
return filepath.ToSlash(dir[len(root):]), true
}
-// hasPathPrefix reports whether the path s begins with the
-// elements in prefix.
-func hasPathPrefix(s, prefix string) bool {
- switch {
- default:
- return false
- case len(s) == len(prefix):
- return s == prefix
- case len(s) > len(prefix):
- if prefix != "" && prefix[len(prefix)-1] == '/' {
- return strings.HasPrefix(s, prefix)
- }
- return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
- }
-}
-
// expandPath returns the symlink-expanded form of path.
func expandPath(p string) string {
x, err := filepath.EvalSymlinks(p)
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index b5a27c6306..28d3f9f847 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -22,7 +22,10 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/search"
"cmd/go/internal/str"
+ "cmd/go/internal/vgo"
)
var IgnoreImports bool // control whether we ignore imports in packages
@@ -99,6 +102,8 @@ type PackagePublic struct {
TestImports []string `json:",omitempty"` // imports from TestGoFiles
XTestGoFiles []string `json:",omitempty"` // _test.go files outside package
XTestImports []string `json:",omitempty"` // imports from XTestGoFiles
+
+ Module *modinfo.ModulePublic `json:",omitempty"` // info about package module
}
// AllFiles returns the names of all the files considered for the package.
@@ -148,6 +153,7 @@ type PackageInternal struct {
CoverVars map[string]*CoverVar // variables created by coverage analysis
OmitDebug bool // tell linker not to write debug information
GobinSubdir bool // install target would be subdir of GOBIN
+ BuildInfo string // add this info to package main
TestmainGo *[]byte // content for _testmain.go
Asmflags []string // -asmflags for this package
@@ -236,7 +242,7 @@ func (p *Package) copyBuild(pp *build.Package) {
// TODO? Target
p.Goroot = pp.Goroot
- p.Standard = p.Goroot && p.ImportPath != "" && isStandardImportPath(p.ImportPath)
+ p.Standard = p.Goroot && p.ImportPath != "" && search.IsStandardImportPath(p.ImportPath)
p.GoFiles = pp.GoFiles
p.CgoFiles = pp.CgoFiles
p.IgnoredGoFiles = pp.IgnoredGoFiles
@@ -276,19 +282,6 @@ func (p *Package) copyBuild(pp *build.Package) {
}
}
-// isStandardImportPath reports whether $GOROOT/src/path should be considered
-// part of the standard distribution. For historical reasons we allow people to add
-// their own code to $GOROOT instead of using $GOPATH, but we assume that
-// code will start with a domain name (dot in the first element).
-func isStandardImportPath(path string) bool {
- i := strings.Index(path, "/")
- if i < 0 {
- i = len(path)
- }
- elem := path[:i]
- return !strings.Contains(elem, ".")
-}
-
// A PackageError describes an error loading information about a package.
type PackageError struct {
ImportStack []string // shortest path from package named on command line to this one
@@ -436,8 +429,20 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
importPath := path
origPath := path
isLocal := build.IsLocalImport(path)
+ var vgoDir string
+ var vgoErr error
if isLocal {
importPath = dirToImportPath(filepath.Join(srcDir, path))
+ } else if vgo.Enabled() {
+ parentPath := ""
+ if parent != nil {
+ parentPath = parent.ImportPath
+ }
+ var p string
+ vgoDir, p, vgoErr = vgo.Lookup(parentPath, path)
+ if vgoErr == nil {
+ importPath = p
+ }
} else if mode&ResolveImport != 0 {
// We do our own path resolution, because we want to
// find out the key to use in packageCache without the
@@ -462,17 +467,28 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
// Load package.
// Import always returns bp != nil, even if an error occurs,
// in order to return partial information.
- buildMode := build.ImportComment
- if mode&ResolveImport == 0 || path != origPath {
- // Not vendoring, or we already found the vendored path.
- buildMode |= build.IgnoreVendor
+ var bp *build.Package
+ var err error
+ if vgoDir != "" {
+ bp, err = cfg.BuildContext.ImportDir(vgoDir, 0)
+ } else if vgoErr != nil {
+ bp = new(build.Package)
+ err = fmt.Errorf("unknown import path %q: %v", importPath, vgoErr)
+ } else {
+ buildMode := build.ImportComment
+ if mode&ResolveImport == 0 || path != origPath {
+ // Not vendoring, or we already found the vendored path.
+ buildMode |= build.IgnoreVendor
+ }
+ bp, err = cfg.BuildContext.Import(path, srcDir, buildMode)
}
- bp, err := cfg.BuildContext.Import(path, srcDir, buildMode)
bp.ImportPath = importPath
if cfg.GOBIN != "" {
bp.BinDir = cfg.GOBIN
+ } else if vgo.Enabled() {
+ bp.BinDir = vgo.BinDir()
}
- if err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
+ if vgoDir == "" && err == nil && !isLocal && bp.ImportComment != "" && bp.ImportComment != path &&
!strings.Contains(path, "/vendor/") && !strings.HasPrefix(path, "vendor/") {
err = fmt.Errorf("code in directory %s expects import %q", bp.Dir, bp.ImportComment)
}
@@ -481,7 +497,7 @@ func LoadImport(path, srcDir string, parent *Package, stk *ImportStack, importPo
p = setErrorPos(p, importPos)
}
- if origPath != cleanImport(origPath) {
+ if vgoDir == "" && origPath != cleanImport(origPath) {
p.Error = &PackageError{
ImportStack: stk.Copy(),
Err: fmt.Sprintf("non-canonical import path: %q should be %q", origPath, pathpkg.Clean(origPath)),
@@ -559,6 +575,16 @@ func isDir(path string) bool {
// If vendor expansion doesn't trigger, then the path is also subject to
// Go 1.11 vgo legacy conversion (golang.org/issue/25069).
func ResolveImportPath(parent *Package, path string) (found string) {
+ if vgo.Enabled() {
+ parentPath := ""
+ if parent != nil {
+ parentPath = parent.ImportPath
+ }
+ if _, p, e := vgo.Lookup(parentPath, path); e == nil {
+ return p
+ }
+ return path
+ }
found = VendoredImportPath(parent, path)
if found != path {
return found
@@ -908,7 +934,7 @@ func disallowInternal(srcDir string, p *Package, stk *ImportStack) *Package {
perr := *p
perr.Error = &PackageError{
ImportStack: stk.Copy(),
- Err: "use of internal package not allowed",
+ Err: "use of internal package " + p.ImportPath + " not allowed",
}
perr.Incomplete = true
return &perr
@@ -1136,6 +1162,9 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
// Install cross-compiled binaries to subdirectories of bin.
elem = full
}
+ if p.Internal.Build.BinDir == "" && vgo.Enabled() {
+ p.Internal.Build.BinDir = vgo.BinDir()
+ }
if p.Internal.Build.BinDir != "" {
// Install to GOBIN or bin of GOPATH entry.
p.Target = filepath.Join(p.Internal.Build.BinDir, elem)
@@ -1386,6 +1415,13 @@ func (p *Package) load(stk *ImportStack, bp *build.Package, err error) {
setError(fmt.Sprintf("case-insensitive import collision: %q and %q", p.ImportPath, other))
return
}
+
+ if vgo.Enabled() {
+ p.Module = vgo.PackageModuleInfo(p.ImportPath)
+ if p.Name == "main" {
+ p.Internal.BuildInfo = vgo.PackageBuildInfo(p.ImportPath, p.Deps)
+ }
+ }
}
// SafeArg reports whether arg is a "safe" command-line argument,
@@ -1660,6 +1696,20 @@ func PackagesAndErrors(args []string) []*Package {
return pkgs
}
+func ImportPaths(args []string) []string {
+ if cmdlineMatchers == nil {
+ SetCmdlinePatterns(search.CleanImportPaths(args))
+ }
+ return vgo.ImportPaths(args)
+}
+
+func ImportPathsForGoGet(args []string) []string {
+ if cmdlineMatchers == nil {
+ SetCmdlinePatterns(search.CleanImportPaths(args))
+ }
+ return search.ImportPathsNoDotExpansion(args)
+}
+
// packagesForBuild is like 'packages' but fails if any of
// the packages or their dependencies have errors
// (cannot be built).
@@ -1745,6 +1795,8 @@ func GoFilesPackage(gofiles []string) *Package {
}
ctxt.ReadDir = func(string) ([]os.FileInfo, error) { return dirent, nil }
+ vgo.AddImports(gofiles)
+
var err error
if dir == "" {
dir = base.Cwd
@@ -1773,6 +1825,8 @@ func GoFilesPackage(gofiles []string) *Package {
}
if cfg.GOBIN != "" {
pkg.Target = filepath.Join(cfg.GOBIN, exe)
+ } else if vgo.Enabled() {
+ pkg.Target = filepath.Join(vgo.BinDir(), exe)
}
}
diff --git a/src/cmd/go/internal/load/search.go b/src/cmd/go/internal/load/search.go
index 6494f8e569..49433984a8 100644
--- a/src/cmd/go/internal/load/search.go
+++ b/src/cmd/go/internal/load/search.go
@@ -5,267 +5,12 @@
package load
import (
- "cmd/go/internal/cfg"
- "fmt"
- "go/build"
- "log"
- "os"
- "path"
"path/filepath"
- "regexp"
"runtime"
"strings"
-)
-
-// allPackages returns all the packages that can be found
-// under the $GOPATH directories and $GOROOT matching pattern.
-// The pattern is either "all" (all packages), "std" (standard packages),
-// "cmd" (standard commands), or a path including "...".
-func allPackages(pattern string) []string {
- pkgs := MatchPackages(pattern)
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
- return pkgs
-}
-
-// allPackagesInFS is like allPackages but is passed a pattern
-// beginning ./ or ../, meaning it should scan the tree rooted
-// at the given directory. There are ... in the pattern too.
-func allPackagesInFS(pattern string) []string {
- pkgs := MatchPackagesInFS(pattern)
- if len(pkgs) == 0 {
- fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
- }
- return pkgs
-}
-
-// MatchPackages returns a list of package paths matching pattern
-// (see go help packages for pattern syntax).
-func MatchPackages(pattern string) []string {
- match := func(string) bool { return true }
- treeCanMatch := func(string) bool { return true }
- if !IsMetaPackage(pattern) {
- match = matchPattern(pattern)
- treeCanMatch = treeCanMatchPattern(pattern)
- }
-
- have := map[string]bool{
- "builtin": true, // ignore pseudo-package that exists only for documentation
- }
- if !cfg.BuildContext.CgoEnabled {
- have["runtime/cgo"] = true // ignore during walk
- }
- var pkgs []string
- for _, src := range cfg.BuildContext.SrcDirs() {
- if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
- continue
- }
- src = filepath.Clean(src) + string(filepath.Separator)
- root := src
- if pattern == "cmd" {
- root += "cmd" + string(filepath.Separator)
- }
- filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil || path == src {
- return nil
- }
-
- want := true
- // Avoid .foo, _foo, and testdata directory trees.
- _, elem := filepath.Split(path)
- if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
- want = false
- }
-
- name := filepath.ToSlash(path[len(src):])
- if pattern == "std" && (!isStandardImportPath(name) || name == "cmd") {
- // The name "std" is only the standard library.
- // If the name is cmd, it's the root of the command tree.
- want = false
- }
- if !treeCanMatch(name) {
- want = false
- }
-
- if !fi.IsDir() {
- if fi.Mode()&os.ModeSymlink != 0 && want {
- if target, err := os.Stat(path); err == nil && target.IsDir() {
- fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
- }
- }
- return nil
- }
- if !want {
- return filepath.SkipDir
- }
-
- if have[name] {
- return nil
- }
- have[name] = true
- if !match(name) {
- return nil
- }
- pkg, err := cfg.BuildContext.ImportDir(path, 0)
- if err != nil {
- if _, noGo := err.(*build.NoGoError); noGo {
- return nil
- }
- }
-
- // If we are expanding "cmd", skip main
- // packages under cmd/vendor. At least as of
- // March, 2017, there is one there for the
- // vendored pprof tool.
- if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
- return nil
- }
-
- pkgs = append(pkgs, name)
- return nil
- })
- }
- return pkgs
-}
-
-// MatchPackagesInFS returns a list of package paths matching pattern,
-// which must begin with ./ or ../
-// (see go help packages for pattern syntax).
-func MatchPackagesInFS(pattern string) []string {
- // Find directory to begin the scan.
- // Could be smarter but this one optimization
- // is enough for now, since ... is usually at the
- // end of a path.
- i := strings.Index(pattern, "...")
- dir, _ := path.Split(pattern[:i])
-
- // pattern begins with ./ or ../.
- // path.Clean will discard the ./ but not the ../.
- // We need to preserve the ./ for pattern matching
- // and in the returned import paths.
- prefix := ""
- if strings.HasPrefix(pattern, "./") {
- prefix = "./"
- }
- match := matchPattern(pattern)
-
- var pkgs []string
- filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
- return nil
- }
- if path == dir {
- // filepath.Walk starts at dir and recurses. For the recursive case,
- // the path is the result of filepath.Join, which calls filepath.Clean.
- // The initial case is not Cleaned, though, so we do this explicitly.
- //
- // This converts a path like "./io/" to "io". Without this step, running
- // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
- // package, because prepending the prefix "./" to the unclean path would
- // result in "././io", and match("././io") returns false.
- path = filepath.Clean(path)
- }
-
- // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
- _, elem := filepath.Split(path)
- dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
- if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
- return filepath.SkipDir
- }
-
- name := prefix + filepath.ToSlash(path)
- if !match(name) {
- return nil
- }
-
- // We keep the directory if we can import it, or if we can't import it
- // due to invalid Go source files. This means that directories containing
- // parse errors will be built (and fail) instead of being silently skipped
- // as not matching the pattern. Go 1.5 and earlier skipped, but that
- // behavior means people miss serious mistakes.
- // See golang.org/issue/11407.
- if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
- if _, noGo := err.(*build.NoGoError); !noGo {
- log.Print(err)
- }
- return nil
- }
- pkgs = append(pkgs, name)
- return nil
- })
- return pkgs
-}
-
-// treeCanMatchPattern(pattern)(name) reports whether
-// name or children of name can possibly match pattern.
-// Pattern is the same limited glob accepted by matchPattern.
-func treeCanMatchPattern(pattern string) func(name string) bool {
- wildCard := false
- if i := strings.Index(pattern, "..."); i >= 0 {
- wildCard = true
- pattern = pattern[:i]
- }
- return func(name string) bool {
- return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
- wildCard && strings.HasPrefix(name, pattern)
- }
-}
-
-// matchPattern(pattern)(name) reports whether
-// name matches pattern. Pattern is a limited glob
-// pattern in which '...' means 'any string' and there
-// is no other special syntax.
-// Unfortunately, there are two special cases. Quoting "go help packages":
-//
-// First, /... at the end of the pattern can match an empty string,
-// so that net/... matches both net and packages in its subdirectories, like net/http.
-// Second, any slash-separted pattern element containing a wildcard never
-// participates in a match of the "vendor" element in the path of a vendored
-// package, so that ./... does not match packages in subdirectories of
-// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
-// Note, however, that a directory named vendor that itself contains code
-// is not a vendored package: cmd/vendor would be a command named vendor,
-// and the pattern cmd/... matches it.
-func matchPattern(pattern string) func(name string) bool {
- // Convert pattern to regular expression.
- // The strategy for the trailing /... is to nest it in an explicit ? expression.
- // The strategy for the vendor exclusion is to change the unmatchable
- // vendor strings to a disallowed code point (vendorChar) and to use
- // "(anything but that codepoint)*" as the implementation of the ... wildcard.
- // This is a bit complicated but the obvious alternative,
- // namely a hand-written search like in most shell glob matchers,
- // is too easy to make accidentally exponential.
- // Using package regexp guarantees linear-time matching.
-
- const vendorChar = "\x00"
-
- if strings.Contains(pattern, vendorChar) {
- return func(name string) bool { return false }
- }
-
- re := regexp.QuoteMeta(pattern)
- re = replaceVendor(re, vendorChar)
- switch {
- case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
- re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
- case re == vendorChar+`/\.\.\.`:
- re = `(/vendor|/` + vendorChar + `/\.\.\.)`
- case strings.HasSuffix(re, `/\.\.\.`):
- re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
- }
- re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
-
- reg := regexp.MustCompile(`^` + re + `$`)
-
- return func(name string) bool {
- if strings.Contains(name, vendorChar) {
- return false
- }
- return reg.MatchString(replaceVendor(name, vendorChar))
- }
-}
+ "cmd/go/internal/search"
+)
// MatchPackage(pattern, cwd)(p) reports whether package p matches pattern in the working directory cwd.
func MatchPackage(pattern, cwd string) func(*Package) bool {
@@ -284,13 +29,14 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
dir = filepath.Join(cwd, dir)
if pattern == "" {
return func(p *Package) bool {
+ // TODO(rsc): This is wrong. See golang.org/issue/25878.
if runtime.GOOS != "windows" {
return p.Dir == dir
}
return strings.EqualFold(p.Dir, dir)
}
}
- matchPath := matchPattern(pattern)
+ matchPath := search.MatchPattern(pattern)
return func(p *Package) bool {
// Compute relative path to dir and see if it matches the pattern.
rel, err := filepath.Rel(dir, p.Dir)
@@ -311,81 +57,7 @@ func MatchPackage(pattern, cwd string) func(*Package) bool {
case pattern == "cmd":
return func(p *Package) bool { return p.Standard && strings.HasPrefix(p.ImportPath, "cmd/") }
default:
- matchPath := matchPattern(pattern)
+ matchPath := search.MatchPattern(pattern)
return func(p *Package) bool { return matchPath(p.ImportPath) }
}
}
-
-// replaceVendor returns the result of replacing
-// non-trailing vendor path elements in x with repl.
-func replaceVendor(x, repl string) string {
- if !strings.Contains(x, "vendor") {
- return x
- }
- elem := strings.Split(x, "/")
- for i := 0; i < len(elem)-1; i++ {
- if elem[i] == "vendor" {
- elem[i] = repl
- }
- }
- return strings.Join(elem, "/")
-}
-
-// ImportPaths returns the import paths to use for the given command line.
-func ImportPaths(args []string) []string {
- args = ImportPathsNoDotExpansion(args)
- var out []string
- for _, a := range args {
- if strings.Contains(a, "...") {
- if build.IsLocalImport(a) {
- out = append(out, allPackagesInFS(a)...)
- } else {
- out = append(out, allPackages(a)...)
- }
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// ImportPathsNoDotExpansion returns the import paths to use for the given
-// command line, but it does no ... expansion.
-func ImportPathsNoDotExpansion(args []string) []string {
- if cmdlineMatchers == nil {
- SetCmdlinePatterns(args)
- }
- if len(args) == 0 {
- return []string{"."}
- }
- var out []string
- for _, a := range args {
- // Arguments are supposed to be import paths, but
- // as a courtesy to Windows developers, rewrite \ to /
- // in command-line arguments. Handles .\... and so on.
- if filepath.Separator == '\\' {
- a = strings.Replace(a, `\`, `/`, -1)
- }
-
- // Put argument in canonical form, but preserve leading ./.
- if strings.HasPrefix(a, "./") {
- a = "./" + path.Clean(a)
- if a == "./." {
- a = "."
- }
- } else {
- a = path.Clean(a)
- }
- if IsMetaPackage(a) {
- out = append(out, allPackages(a)...)
- continue
- }
- out = append(out, a)
- }
- return out
-}
-
-// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
-func IsMetaPackage(name string) bool {
- return name == "std" || name == "cmd" || name == "all"
-}
diff --git a/src/cmd/go/internal/modconv/dep.go b/src/cmd/go/internal/modconv/dep.go
new file mode 100644
index 0000000000..28dd28a3c2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/dep.go
@@ -0,0 +1,71 @@
+// Copyright 2018 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 modconv
+
+import (
+ "fmt"
+ "strconv"
+ "strings"
+
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+func ParseGopkgLock(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ var r *module.Version
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if i := strings.Index(line, "#"); i >= 0 {
+ line = line[:i]
+ }
+ line = strings.TrimSpace(line)
+ if line == "[[projects]]" {
+ list = append(list, module.Version{})
+ r = &list[len(list)-1]
+ continue
+ }
+ if strings.HasPrefix(line, "[") {
+ r = nil
+ continue
+ }
+ if r == nil {
+ continue
+ }
+ i := strings.Index(line, "=")
+ if i < 0 {
+ continue
+ }
+ key := strings.TrimSpace(line[:i])
+ val := strings.TrimSpace(line[i+1:])
+ if len(val) >= 2 && val[0] == '"' && val[len(val)-1] == '"' {
+ q, err := strconv.Unquote(val) // Go unquoting, but close enough for now
+ if err != nil {
+ return nil, fmt.Errorf("%s:%d: invalid quoted string: %v", file, lineno, err)
+ }
+ val = q
+ }
+ switch key {
+ case "name":
+ r.Path = val
+ case "revision", "version":
+ // Note: key "version" should take priority over "revision",
+ // and it does, because dep writes toml keys in alphabetical order,
+ // so we see version (if present) second.
+ if key == "version" {
+ if !semver.IsValid(val) || semver.Canonical(val) != val {
+ break
+ }
+ }
+ r.Version = val
+ }
+ }
+ for _, r := range list {
+ if r.Path == "" || r.Version == "" {
+ return nil, fmt.Errorf("%s: empty [[projects]] stanza (%s)", file, r.Path)
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/glide.go b/src/cmd/go/internal/modconv/glide.go
new file mode 100644
index 0000000000..abe88c4fc2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/glide.go
@@ -0,0 +1,40 @@
+// Copyright 2018 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 modconv
+
+import (
+ "cmd/go/internal/module"
+ "strings"
+)
+
+func ParseGlideLock(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ imports := false
+ name := ""
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if line == "" {
+ continue
+ }
+ if strings.HasPrefix(line, "imports:") {
+ imports = true
+ } else if line[0] != '-' && line[0] != ' ' && line[0] != '\t' {
+ imports = false
+ }
+ if !imports {
+ continue
+ }
+ if strings.HasPrefix(line, "- name:") {
+ name = strings.TrimSpace(line[len("- name:"):])
+ }
+ if strings.HasPrefix(line, " version:") {
+ version := strings.TrimSpace(line[len(" version:"):])
+ if name != "" && version != "" {
+ list = append(list, module.Version{Path: name, Version: version})
+ }
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/glock.go b/src/cmd/go/internal/modconv/glock.go
new file mode 100644
index 0000000000..57eb66ebf9
--- /dev/null
+++ b/src/cmd/go/internal/modconv/glock.go
@@ -0,0 +1,23 @@
+// Copyright 2018 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 modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/module"
+)
+
+func ParseGLOCKFILE(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ f := strings.Fields(line)
+ if len(f) >= 2 && f[0] != "cmd" {
+ list = append(list, module.Version{Path: f[0], Version: f[1]})
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/godeps.go b/src/cmd/go/internal/modconv/godeps.go
new file mode 100644
index 0000000000..904fd70ea2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/godeps.go
@@ -0,0 +1,29 @@
+// Copyright 2018 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 modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/module"
+)
+
+func ParseGodepsJSON(file string, data []byte) ([]module.Version, error) {
+ var cfg struct {
+ ImportPath string
+ Deps []struct {
+ ImportPath string
+ Rev string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ var list []module.Version
+ for _, d := range cfg.Deps {
+ list = append(list, module.Version{Path: d.ImportPath, Version: d.Rev})
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/modconv.go b/src/cmd/go/internal/modconv/modconv.go
new file mode 100644
index 0000000000..b689b52dee
--- /dev/null
+++ b/src/cmd/go/internal/modconv/modconv.go
@@ -0,0 +1,25 @@
+// Copyright 2018 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 modconv
+
+import "cmd/go/internal/module"
+
+var Converters = map[string]func(string, []byte) ([]module.Version, error){
+ "GLOCKFILE": ParseGLOCKFILE,
+ "Godeps/Godeps.json": ParseGodepsJSON,
+ "Gopkg.lock": ParseGopkgLock,
+ "dependencies.tsv": ParseDependenciesTSV,
+ "glide.lock": ParseGlideLock,
+ "vendor.conf": ParseVendorConf,
+ "vendor.yml": ParseVendorYML,
+ "vendor/manifest": ParseVendorManifest,
+ "vendor/vendor.json": ParseVendorJSON,
+}
+
+// Prefix is a line we write at the top of auto-converted go.mod files
+// for dependencies before caching them.
+// In case of bugs in the converter, if we bump this version number,
+// then all the cached copies will be ignored.
+const Prefix = "//vgo 0.0.4\n"
diff --git a/src/cmd/go/internal/modconv/modconv_test.go b/src/cmd/go/internal/modconv/modconv_test.go
new file mode 100644
index 0000000000..04a1db3f84
--- /dev/null
+++ b/src/cmd/go/internal/modconv/modconv_test.go
@@ -0,0 +1,69 @@
+// Copyright 2018 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 modconv
+
+import (
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "path/filepath"
+ "testing"
+)
+
+var extMap = map[string]string{
+ ".dep": "Gopkg.lock",
+ ".glide": "glide.lock",
+ ".glock": "GLOCKFILE",
+ ".godeps": "Godeps/Godeps.json",
+ ".tsv": "dependencies.tsv",
+ ".vconf": "vendor.conf",
+ ".vjson": "vendor/vendor.json",
+ ".vyml": "vendor.yml",
+ ".vmanifest": "vendor/manifest",
+}
+
+func Test(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tests, _ := filepath.Glob("testdata/*")
+ if len(tests) == 0 {
+ t.Fatalf("no tests found")
+ }
+ for _, test := range tests {
+ file := filepath.Base(test)
+ ext := filepath.Ext(file)
+ if ext == ".out" {
+ continue
+ }
+ t.Run(file, func(t *testing.T) {
+ if extMap[ext] == "" {
+ t.Fatal("unknown extension")
+ }
+ if Converters[extMap[ext]] == nil {
+ t.Fatalf("Converters[%q] == nil", extMap[ext])
+ }
+ data, err := ioutil.ReadFile(test)
+ if err != nil {
+ t.Fatal(err)
+ }
+ out, err := Converters[extMap[ext]](test, data)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want, err := ioutil.ReadFile(test[:len(test)-len(ext)] + ".out")
+ if err != nil {
+ t.Error(err)
+ }
+ var buf bytes.Buffer
+ for _, r := range out {
+ fmt.Fprintf(&buf, "%s %s\n", r.Path, r.Version)
+ }
+ if !bytes.Equal(buf.Bytes(), want) {
+ t.Errorf("have:\n%s\nwant:\n%s", buf.Bytes(), want)
+ }
+ })
+ }
+}
diff --git a/src/cmd/go/internal/modconv/testdata/cockroach.glock b/src/cmd/go/internal/modconv/testdata/cockroach.glock
new file mode 100644
index 0000000000..221c8acdfd
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/cockroach.glock
@@ -0,0 +1,41 @@
+cmd github.com/cockroachdb/c-protobuf/cmd/protoc
+cmd github.com/cockroachdb/yacc
+cmd github.com/gogo/protobuf/protoc-gen-gogo
+cmd github.com/golang/lint/golint
+cmd github.com/jteeuwen/go-bindata/go-bindata
+cmd github.com/kisielk/errcheck
+cmd github.com/robfig/glock
+cmd github.com/tebeka/go2xunit
+cmd golang.org/x/tools/cmd/goimports
+cmd golang.org/x/tools/cmd/stringer
+github.com/agtorre/gocolorize f42b554bf7f006936130c9bb4f971afd2d87f671
+github.com/biogo/store e1f74b3c58befe661feed7fa4cf52436de753128
+github.com/cockroachdb/c-lz4 6e71f140a365017bbe0904710007f8725fd3f809
+github.com/cockroachdb/c-protobuf 0f9ab7b988ca7474cf76b9a961ab03c0552abcb3
+github.com/cockroachdb/c-rocksdb 7fc876fe79b96de0e25069c9ae27e6444637bd54
+github.com/cockroachdb/c-snappy 618733f9e5bab8463b9049117a335a7a1bfc9fd5
+github.com/cockroachdb/yacc 572e006f8e6b0061ebda949d13744f5108389514
+github.com/coreos/etcd 18ecc297bc913bed6fc093d66b1fa22020dba7dc
+github.com/docker/docker 7374852be9def787921aea2ca831771982badecf
+github.com/elazarl/go-bindata-assetfs 3dcc96556217539f50599357fb481ac0dc7439b9
+github.com/gogo/protobuf 98e73e511a62a9c232152f94999112c80142a813
+github.com/golang/lint 7b7f4364ff76043e6c3610281525fabc0d90f0e4
+github.com/google/btree cc6329d4279e3f025a53a83c397d2339b5705c45
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/jteeuwen/go-bindata dce55d09e24ac40a6e725c8420902b86554f8046
+github.com/julienschmidt/httprouter 6aacfd5ab513e34f7e64ea9627ab9670371b34e7
+github.com/kisielk/errcheck 50b84cf7fa18ee2985b8c63ba3de5edd604b9259
+github.com/kisielk/gotool d678387370a2eb9b5b0a33218bc8c9d8de15b6be
+github.com/lib/pq a8d8d01c4f91602f876bf5aa210274e8203a6b45
+github.com/montanaflynn/stats 44fb56da2a2a67d394dec0e18a82dd316f192529
+github.com/peterh/liner 1bb0d1c1a25ed393d8feb09bab039b2b1b1fbced
+github.com/robfig/glock cb3c3ec56de988289cab7bbd284eddc04dfee6c9
+github.com/samalba/dockerclient 12570e600d71374233e5056ba315f657ced496c7
+github.com/spf13/cobra 66816bcd0378e248c613e3c443c020f544c28804
+github.com/spf13/pflag 67cbc198fd11dab704b214c1e629a97af392c085
+github.com/tebeka/go2xunit d45000af2242dd0e7b8c7b07d82a1068adc5fd40
+golang.org/x/crypto cc04154d65fb9296747569b107cfd05380b1ea3e
+golang.org/x/net 8bfde94a845cb31000de3266ac83edbda58dab09
+golang.org/x/text d4cc1b1e16b49d6dafc4982403b40fe89c512cd5
+golang.org/x/tools d02228d1857b9f49cd0252788516ff5584266eb6
+gopkg.in/yaml.v1 9f9df34309c04878acc86042b16630b0f696e1de
diff --git a/src/cmd/go/internal/modconv/testdata/cockroach.out b/src/cmd/go/internal/modconv/testdata/cockroach.out
new file mode 100644
index 0000000000..30cdbb7bf2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/cockroach.out
@@ -0,0 +1,31 @@
+github.com/agtorre/gocolorize f42b554bf7f006936130c9bb4f971afd2d87f671
+github.com/biogo/store e1f74b3c58befe661feed7fa4cf52436de753128
+github.com/cockroachdb/c-lz4 6e71f140a365017bbe0904710007f8725fd3f809
+github.com/cockroachdb/c-protobuf 0f9ab7b988ca7474cf76b9a961ab03c0552abcb3
+github.com/cockroachdb/c-rocksdb 7fc876fe79b96de0e25069c9ae27e6444637bd54
+github.com/cockroachdb/c-snappy 618733f9e5bab8463b9049117a335a7a1bfc9fd5
+github.com/cockroachdb/yacc 572e006f8e6b0061ebda949d13744f5108389514
+github.com/coreos/etcd 18ecc297bc913bed6fc093d66b1fa22020dba7dc
+github.com/docker/docker 7374852be9def787921aea2ca831771982badecf
+github.com/elazarl/go-bindata-assetfs 3dcc96556217539f50599357fb481ac0dc7439b9
+github.com/gogo/protobuf 98e73e511a62a9c232152f94999112c80142a813
+github.com/golang/lint 7b7f4364ff76043e6c3610281525fabc0d90f0e4
+github.com/google/btree cc6329d4279e3f025a53a83c397d2339b5705c45
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/jteeuwen/go-bindata dce55d09e24ac40a6e725c8420902b86554f8046
+github.com/julienschmidt/httprouter 6aacfd5ab513e34f7e64ea9627ab9670371b34e7
+github.com/kisielk/errcheck 50b84cf7fa18ee2985b8c63ba3de5edd604b9259
+github.com/kisielk/gotool d678387370a2eb9b5b0a33218bc8c9d8de15b6be
+github.com/lib/pq a8d8d01c4f91602f876bf5aa210274e8203a6b45
+github.com/montanaflynn/stats 44fb56da2a2a67d394dec0e18a82dd316f192529
+github.com/peterh/liner 1bb0d1c1a25ed393d8feb09bab039b2b1b1fbced
+github.com/robfig/glock cb3c3ec56de988289cab7bbd284eddc04dfee6c9
+github.com/samalba/dockerclient 12570e600d71374233e5056ba315f657ced496c7
+github.com/spf13/cobra 66816bcd0378e248c613e3c443c020f544c28804
+github.com/spf13/pflag 67cbc198fd11dab704b214c1e629a97af392c085
+github.com/tebeka/go2xunit d45000af2242dd0e7b8c7b07d82a1068adc5fd40
+golang.org/x/crypto cc04154d65fb9296747569b107cfd05380b1ea3e
+golang.org/x/net 8bfde94a845cb31000de3266ac83edbda58dab09
+golang.org/x/text d4cc1b1e16b49d6dafc4982403b40fe89c512cd5
+golang.org/x/tools d02228d1857b9f49cd0252788516ff5584266eb6
+gopkg.in/yaml.v1 9f9df34309c04878acc86042b16630b0f696e1de
diff --git a/src/cmd/go/internal/modconv/testdata/dockermachine.godeps b/src/cmd/go/internal/modconv/testdata/dockermachine.godeps
new file mode 100644
index 0000000000..a551002a04
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/dockermachine.godeps
@@ -0,0 +1,159 @@
+{
+ "ImportPath": "github.com/docker/machine",
+ "GoVersion": "go1.4.2",
+ "Deps": [
+ {
+ "ImportPath": "code.google.com/p/goauth2/oauth",
+ "Comment": "weekly-56",
+ "Rev": "afe77d958c701557ec5dc56f6936fcc194d15520"
+ },
+ {
+ "ImportPath": "github.com/MSOpenTech/azure-sdk-for-go",
+ "Comment": "v1.1-17-g515f3ec",
+ "Rev": "515f3ec74ce6a5b31e934cefae997c97bd0a1b1e"
+ },
+ {
+ "ImportPath": "github.com/cenkalti/backoff",
+ "Rev": "9831e1e25c874e0a0601b6dc43641071414eec7a"
+ },
+ {
+ "ImportPath": "github.com/codegangsta/cli",
+ "Comment": "1.2.0-64-ge1712f3",
+ "Rev": "e1712f381785e32046927f64a7c86fe569203196"
+ },
+ {
+ "ImportPath": "github.com/digitalocean/godo",
+ "Comment": "v0.5.0",
+ "Rev": "5478aae80694de1d2d0e02c386bbedd201266234"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/dockerversion",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/engine",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/archive",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/fileutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/ioutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/mflag",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/parsers",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/pools",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/promise",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/system",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/term",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/timeutils",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/units",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/pkg/version",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar",
+ "Comment": "v1.5.0",
+ "Rev": "a8a31eff10544860d2188dddabdee4d727545796"
+ },
+ {
+ "ImportPath": "github.com/docker/libtrust",
+ "Rev": "c54fbb67c1f1e68d7d6f8d2ad7c9360404616a41"
+ },
+ {
+ "ImportPath": "github.com/google/go-querystring/query",
+ "Rev": "30f7a39f4a218feb5325f3aebc60c32a572a8274"
+ },
+ {
+ "ImportPath": "github.com/mitchellh/mapstructure",
+ "Rev": "740c764bc6149d3f1806231418adb9f52c11bcbf"
+ },
+ {
+ "ImportPath": "github.com/rackspace/gophercloud",
+ "Comment": "v1.0.0-558-ce0f487",
+ "Rev": "ce0f487f6747ab43c4e4404722df25349385bebd"
+ },
+ {
+ "ImportPath": "github.com/skarademir/naturalsort",
+ "Rev": "983d4d86054d80f91fd04dd62ec52c1d078ce403"
+ },
+ {
+ "ImportPath": "github.com/smartystreets/go-aws-auth",
+ "Rev": "1f0db8c0ee6362470abe06a94e3385927ed72a4b"
+ },
+ {
+ "ImportPath": "github.com/stretchr/testify/assert",
+ "Rev": "e4ec8152c15fc46bd5056ce65997a07c7d415325"
+ },
+ {
+ "ImportPath": "github.com/pyr/egoscale/src/egoscale",
+ "Rev": "bbaa67324aeeacc90430c1fe0a9c620d3929512e"
+ },
+ {
+ "ImportPath": "github.com/tent/http-link-go",
+ "Rev": "ac974c61c2f990f4115b119354b5e0b47550e888"
+ },
+ {
+ "ImportPath": "github.com/vmware/govcloudair",
+ "Comment": "v0.0.2",
+ "Rev": "66a23eaabc61518f91769939ff541886fe1dceef"
+ },
+ {
+ "ImportPath": "golang.org/x/crypto/ssh",
+ "Rev": "1fbbd62cfec66bd39d91e97749579579d4d3037e"
+ },
+ {
+ "ImportPath": "google.golang.org/api/compute/v1",
+ "Rev": "aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5"
+ },
+ {
+ "ImportPath": "google.golang.org/api/googleapi",
+ "Rev": "aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5"
+ }
+ ]
+}
diff --git a/src/cmd/go/internal/modconv/testdata/dockermachine.out b/src/cmd/go/internal/modconv/testdata/dockermachine.out
new file mode 100644
index 0000000000..0b39ceaccb
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/dockermachine.out
@@ -0,0 +1,33 @@
+code.google.com/p/goauth2/oauth afe77d958c701557ec5dc56f6936fcc194d15520
+github.com/MSOpenTech/azure-sdk-for-go 515f3ec74ce6a5b31e934cefae997c97bd0a1b1e
+github.com/cenkalti/backoff 9831e1e25c874e0a0601b6dc43641071414eec7a
+github.com/codegangsta/cli e1712f381785e32046927f64a7c86fe569203196
+github.com/digitalocean/godo 5478aae80694de1d2d0e02c386bbedd201266234
+github.com/docker/docker/dockerversion a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/engine a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/archive a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/fileutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/ioutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/mflag a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/parsers a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/pools a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/promise a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/system a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/term a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/timeutils a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/units a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/pkg/version a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/docker/vendor/src/code.google.com/p/go/src/pkg/archive/tar a8a31eff10544860d2188dddabdee4d727545796
+github.com/docker/libtrust c54fbb67c1f1e68d7d6f8d2ad7c9360404616a41
+github.com/google/go-querystring/query 30f7a39f4a218feb5325f3aebc60c32a572a8274
+github.com/mitchellh/mapstructure 740c764bc6149d3f1806231418adb9f52c11bcbf
+github.com/rackspace/gophercloud ce0f487f6747ab43c4e4404722df25349385bebd
+github.com/skarademir/naturalsort 983d4d86054d80f91fd04dd62ec52c1d078ce403
+github.com/smartystreets/go-aws-auth 1f0db8c0ee6362470abe06a94e3385927ed72a4b
+github.com/stretchr/testify/assert e4ec8152c15fc46bd5056ce65997a07c7d415325
+github.com/pyr/egoscale/src/egoscale bbaa67324aeeacc90430c1fe0a9c620d3929512e
+github.com/tent/http-link-go ac974c61c2f990f4115b119354b5e0b47550e888
+github.com/vmware/govcloudair 66a23eaabc61518f91769939ff541886fe1dceef
+golang.org/x/crypto/ssh 1fbbd62cfec66bd39d91e97749579579d4d3037e
+google.golang.org/api/compute/v1 aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5
+google.golang.org/api/googleapi aa91ac681e18e52b1a0dfe29b9d8354e88c0dcf5
diff --git a/src/cmd/go/internal/modconv/testdata/dockerman.glide b/src/cmd/go/internal/modconv/testdata/dockerman.glide
new file mode 100644
index 0000000000..5ec765a4c6
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/dockerman.glide
@@ -0,0 +1,52 @@
+hash: ead3ea293a6143fe41069ebec814bf197d8c43a92cc7666b1f7e21a419b46feb
+updated: 2016-06-20T21:53:35.420817456Z
+imports:
+- name: github.com/BurntSushi/toml
+ version: f0aeabca5a127c4078abb8c8d64298b147264b55
+- name: github.com/cpuguy83/go-md2man
+ version: a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
+ subpackages:
+ - md2man
+- name: github.com/fsnotify/fsnotify
+ version: 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+- name: github.com/hashicorp/hcl
+ version: da486364306ed66c218be9b7953e19173447c18b
+ subpackages:
+ - hcl/ast
+ - hcl/parser
+ - hcl/token
+ - json/parser
+ - hcl/scanner
+ - hcl/strconv
+ - json/scanner
+ - json/token
+- name: github.com/inconshreveable/mousetrap
+ version: 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+- name: github.com/magiconair/properties
+ version: c265cfa48dda6474e208715ca93e987829f572f8
+- name: github.com/mitchellh/mapstructure
+ version: d2dd0262208475919e1a362f675cfc0e7c10e905
+- name: github.com/russross/blackfriday
+ version: 1d6b8e9301e720b08a8938b8c25c018285885438
+- name: github.com/shurcooL/sanitized_anchor_name
+ version: 10ef21a441db47d8b13ebcc5fd2310f636973c77
+- name: github.com/spf13/cast
+ version: 27b586b42e29bec072fe7379259cc719e1289da6
+- name: github.com/spf13/jwalterweatherman
+ version: 33c24e77fb80341fe7130ee7c594256ff08ccc46
+- name: github.com/spf13/pflag
+ version: dabebe21bf790f782ea4c7bbd2efc430de182afd
+- name: github.com/spf13/viper
+ version: c1ccc378a054ea8d4e38d8c67f6938d4760b53dd
+- name: golang.org/x/sys
+ version: 62bee037599929a6e9146f29d10dd5208c43507d
+ subpackages:
+ - unix
+- name: gopkg.in/yaml.v2
+ version: a83829b6f1293c91addabc89d0571c246397bbf4
+- name: github.com/spf13/cobra
+ repo: https://github.com/dnephin/cobra
+ subpackages:
+ - doc
+ version: v1.3
+devImports: []
diff --git a/src/cmd/go/internal/modconv/testdata/dockerman.out b/src/cmd/go/internal/modconv/testdata/dockerman.out
new file mode 100644
index 0000000000..5e6370b31c
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/dockerman.out
@@ -0,0 +1,16 @@
+github.com/BurntSushi/toml f0aeabca5a127c4078abb8c8d64298b147264b55
+github.com/cpuguy83/go-md2man a65d4d2de4d5f7c74868dfa9b202a3c8be315aaa
+github.com/fsnotify/fsnotify 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+github.com/hashicorp/hcl da486364306ed66c218be9b7953e19173447c18b
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/magiconair/properties c265cfa48dda6474e208715ca93e987829f572f8
+github.com/mitchellh/mapstructure d2dd0262208475919e1a362f675cfc0e7c10e905
+github.com/russross/blackfriday 1d6b8e9301e720b08a8938b8c25c018285885438
+github.com/shurcooL/sanitized_anchor_name 10ef21a441db47d8b13ebcc5fd2310f636973c77
+github.com/spf13/cast 27b586b42e29bec072fe7379259cc719e1289da6
+github.com/spf13/jwalterweatherman 33c24e77fb80341fe7130ee7c594256ff08ccc46
+github.com/spf13/pflag dabebe21bf790f782ea4c7bbd2efc430de182afd
+github.com/spf13/viper c1ccc378a054ea8d4e38d8c67f6938d4760b53dd
+golang.org/x/sys 62bee037599929a6e9146f29d10dd5208c43507d
+gopkg.in/yaml.v2 a83829b6f1293c91addabc89d0571c246397bbf4
+github.com/spf13/cobra v1.3
diff --git a/src/cmd/go/internal/modconv/testdata/govmomi.out b/src/cmd/go/internal/modconv/testdata/govmomi.out
new file mode 100644
index 0000000000..188c458b3d
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/govmomi.out
@@ -0,0 +1,5 @@
+github.com/davecgh/go-xdr/xdr2 4930550ba2e22f87187498acfd78348b15f4e7a8
+github.com/google/uuid 6a5e28554805e78ea6141142aba763936c4761c0
+github.com/kr/pretty 2ee9d7453c02ef7fa518a83ae23644eb8872186a
+github.com/kr/pty 95d05c1eef33a45bd58676b6ce28d105839b8d0b
+github.com/vmware/vmw-guestinfo 25eff159a728be87e103a0b8045e08273f4dbec4
diff --git a/src/cmd/go/internal/modconv/testdata/govmomi.vmanifest b/src/cmd/go/internal/modconv/testdata/govmomi.vmanifest
new file mode 100644
index 0000000000..b89e4ab5ee
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/govmomi.vmanifest
@@ -0,0 +1,46 @@
+{
+ "version": 0,
+ "dependencies": [
+ {
+ "importpath": "github.com/davecgh/go-xdr/xdr2",
+ "repository": "https://github.com/rasky/go-xdr",
+ "vcs": "git",
+ "revision": "4930550ba2e22f87187498acfd78348b15f4e7a8",
+ "branch": "improvements",
+ "path": "/xdr2",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/google/uuid",
+ "repository": "https://github.com/google/uuid",
+ "vcs": "git",
+ "revision": "6a5e28554805e78ea6141142aba763936c4761c0",
+ "branch": "master",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/kr/pretty",
+ "repository": "https://github.com/dougm/pretty",
+ "vcs": "git",
+ "revision": "2ee9d7453c02ef7fa518a83ae23644eb8872186a",
+ "branch": "govmomi",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/kr/pty",
+ "repository": "https://github.com/kr/pty",
+ "vcs": "git",
+ "revision": "95d05c1eef33a45bd58676b6ce28d105839b8d0b",
+ "branch": "master",
+ "notests": true
+ },
+ {
+ "importpath": "github.com/vmware/vmw-guestinfo",
+ "repository": "https://github.com/vmware/vmw-guestinfo",
+ "vcs": "git",
+ "revision": "25eff159a728be87e103a0b8045e08273f4dbec4",
+ "branch": "master",
+ "notests": true
+ }
+ ]
+}
diff --git a/src/cmd/go/internal/modconv/testdata/juju.out b/src/cmd/go/internal/modconv/testdata/juju.out
new file mode 100644
index 0000000000..c2430b1e26
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/juju.out
@@ -0,0 +1,106 @@
+github.com/Azure/azure-sdk-for-go 902d95d9f311ae585ee98cfd18f418b467d60d5a
+github.com/Azure/go-autorest 6f40a8acfe03270d792cb8155e2942c09d7cff95
+github.com/ajstarks/svgo 89e3ac64b5b3e403a5e7c35ea4f98d45db7b4518
+github.com/altoros/gosigma 31228935eec685587914528585da4eb9b073c76d
+github.com/beorn7/perks 3ac7bf7a47d159a033b107610db8a1b6575507a4
+github.com/bmizerany/pat c068ca2f0aacee5ac3681d68e4d0a003b7d1fd2c
+github.com/coreos/go-systemd 7b2428fec40033549c68f54e26e89e7ca9a9ce31
+github.com/dgrijalva/jwt-go 01aeca54ebda6e0fbfafd0a524d234159c05ec20
+github.com/dustin/go-humanize 145fabdb1ab757076a70a886d092a3af27f66f4c
+github.com/godbus/dbus 32c6cc29c14570de4cf6d7e7737d68fb2d01ad15
+github.com/golang/protobuf 4bd1920723d7b7c925de087aa32e2187708897f7
+github.com/google/go-querystring 9235644dd9e52eeae6fa48efd539fdc351a0af53
+github.com/gorilla/schema 08023a0215e7fc27a9aecd8b8c50913c40019478
+github.com/gorilla/websocket 804cb600d06b10672f2fbc0a336a7bee507a428e
+github.com/gosuri/uitable 36ee7e946282a3fb1cfecd476ddc9b35d8847e42
+github.com/joyent/gocommon ade826b8b54e81a779ccb29d358a45ba24b7809c
+github.com/joyent/gosdc 2f11feadd2d9891e92296a1077c3e2e56939547d
+github.com/joyent/gosign 0da0d5f1342065321c97812b1f4ac0c2b0bab56c
+github.com/juju/ansiterm b99631de12cf04a906c1d4e4ec54fb86eae5863d
+github.com/juju/blobstore 06056004b3d7b54bbb7984d830c537bad00fec21
+github.com/juju/bundlechanges 7725027b95e0d54635e0fb11efc2debdcdf19f75
+github.com/juju/cmd 9425a576247f348b9b40afe3b60085de63470de5
+github.com/juju/description d3742c23561884cd7d759ef7142340af1d22cab0
+github.com/juju/errors 1b5e39b83d1835fa480e0c2ddefb040ee82d58b3
+github.com/juju/gnuflag 4e76c56581859c14d9d87e1ddbe29e1c0f10195f
+github.com/juju/go4 40d72ab9641a2a8c36a9c46a51e28367115c8e59
+github.com/juju/gojsonpointer afe8b77aa08f272b49e01b82de78510c11f61500
+github.com/juju/gojsonreference f0d24ac5ee330baa21721cdff56d45e4ee42628e
+github.com/juju/gojsonschema e1ad140384f254c82f89450d9a7c8dd38a632838
+github.com/juju/gomaasapi cfbc096bd45f276c17a391efc4db710b60ae3ad7
+github.com/juju/httpprof 14bf14c307672fd2456bdbf35d19cf0ccd3cf565
+github.com/juju/httprequest 266fd1e9debf09c037a63f074d099a2da4559ece
+github.com/juju/idmclient 4dc25171f675da4206b71695d3fd80e519ad05c1
+github.com/juju/jsonschema a0ef8b74ebcffeeff9fc374854deb4af388f037e
+github.com/juju/loggo 21bc4c63e8b435779a080e39e592969b7b90b889
+github.com/juju/mempool 24974d6c264fe5a29716e7d56ea24c4bd904b7cc
+github.com/juju/mutex 59c26ee163447c5c57f63ff71610d433862013de
+github.com/juju/persistent-cookiejar 5243747bf8f2d0897f6c7a52799327dc97d585e8
+github.com/juju/pubsub 9dcaca7eb4340dbf685aa7b3ad4cc4f8691a33d4
+github.com/juju/replicaset 6b5becf2232ce76656ea765d8d915d41755a1513
+github.com/juju/retry 62c62032529169c7ec02fa48f93349604c345e1f
+github.com/juju/rfc ebdbbdb950cd039a531d15cdc2ac2cbd94f068ee
+github.com/juju/romulus 98d6700423d63971f10ca14afea9ecf2b9b99f0f
+github.com/juju/schema 075de04f9b7d7580d60a1e12a0b3f50bb18e6998
+github.com/juju/terms-client 9b925afd677234e4146dde3cb1a11e187cbed64e
+github.com/juju/testing fce9bc4ebf7a77310c262ac4884e03b778eae06a
+github.com/juju/txn 28898197906200d603394d8e4ce537436529f1c5
+github.com/juju/usso 68a59c96c178fbbad65926e7f93db50a2cd14f33
+github.com/juju/utils 9f8aeb9b09e2d8c769be8317ccfa23f7eec62c26
+github.com/juju/version 1f41e27e54f21acccf9b2dddae063a782a8a7ceb
+github.com/juju/webbrowser 54b8c57083b4afb7dc75da7f13e2967b2606a507
+github.com/juju/xml eb759a627588d35166bc505fceb51b88500e291e
+github.com/juju/zip f6b1e93fa2e29a1d7d49b566b2b51efb060c982a
+github.com/julienschmidt/httprouter 77a895ad01ebc98a4dc95d8355bc825ce80a56f6
+github.com/lestrrat/go-jspointer f4881e611bdbe9fb413a7780721ef8400a1f2341
+github.com/lestrrat/go-jsref e452c7b5801d1c6494c9e7e0cbc7498c0f88dfd1
+github.com/lestrrat/go-jsschema b09d7650b822d2ea3dc83d5091a5e2acd8330051
+github.com/lestrrat/go-jsval b1258a10419fe0693f7b35ad65cd5074bc0ba1e5
+github.com/lestrrat/go-pdebug 2e6eaaa5717f81bda41d27070d3c966f40a1e75f
+github.com/lestrrat/go-structinfo f74c056fe41f860aa6264478c664a6fff8a64298
+github.com/lunixbochs/vtclean 4fbf7632a2c6d3fbdb9931439bdbbeded02cbe36
+github.com/lxc/lxd 23da0234979fa6299565b91b529a6dbeb42ee36d
+github.com/masterzen/azure-sdk-for-go ee4f0065d00cd12b542f18f5bc45799e88163b12
+github.com/masterzen/simplexml 4572e39b1ab9fe03ee513ce6fc7e289e98482190
+github.com/masterzen/winrm 7a535cd943fccaeed196718896beec3fb51aff41
+github.com/masterzen/xmlpath 13f4951698adc0fa9c1dda3e275d489a24201161
+github.com/mattn/go-colorable ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8
+github.com/mattn/go-isatty 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8
+github.com/mattn/go-runewidth d96d1bd051f2bd9e7e43d602782b37b93b1b5666
+github.com/matttproud/golang_protobuf_extensions c12348ce28de40eed0136aa2b644d0ee0650e56c
+github.com/nu7hatch/gouuid 179d4d0c4d8d407a32af483c2354df1d2c91e6c3
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/prometheus/client_golang 575f371f7862609249a1be4c9145f429fe065e32
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common dd586c1c5abb0be59e60f942c22af711a2008cb4
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/rogpeppe/fastuuid 6724a57986aff9bff1a1770e9347036def7c89f6
+github.com/vmware/govmomi c0c7ce63df7edd78e713257b924c89d9a2dac119
+golang.org/x/crypto 8e06e8ddd9629eb88639aba897641bff8031f1d3
+golang.org/x/net ea47fc708ee3e20177f3ca3716217c4ab75942cb
+golang.org/x/oauth2 11c60b6f71a6ad48ed6f93c65fa4c6f9b1b5b46a
+golang.org/x/sys 7a6e5648d140666db5d920909e082ca00a87ba2c
+golang.org/x/text 2910a502d2bf9e43193af9d68ca516529614eed3
+google.golang.org/api 0d3983fb069cb6651353fc44c5cb604e263f2a93
+google.golang.org/cloud f20d6dcccb44ed49de45ae3703312cb46e627db1
+gopkg.in/amz.v3 8c3190dff075bf5442c9eedbf8f8ed6144a099e7
+gopkg.in/check.v1 4f90aeace3a26ad7021961c297b22c42160c7b25
+gopkg.in/errgo.v1 442357a80af5c6bf9b6d51ae791a39c3421004f3
+gopkg.in/goose.v1 ac43167b647feacdd9a1e34ee81e574551bc748d
+gopkg.in/ini.v1 776aa739ce9373377cd16f526cdf06cb4c89b40f
+gopkg.in/juju/blobstore.v2 51fa6e26128d74e445c72d3a91af555151cc3654
+gopkg.in/juju/charm.v6-unstable 83771c4919d6810bce5b7e63f46bea5fbfed0b93
+gopkg.in/juju/charmrepo.v2-unstable e79aa298df89ea887c9bffec46063c24bfb730f7
+gopkg.in/juju/charmstore.v5-unstable fd1eef3002fc6b6daff5e97efab6f5056d22dcc7
+gopkg.in/juju/environschema.v1 7359fc7857abe2b11b5b3e23811a9c64cb6b01e0
+gopkg.in/juju/jujusvg.v2 d82160011935ef79fc7aca84aba2c6f74700fe75
+gopkg.in/juju/names.v2 0847c26d322a121e52614f969fb82eae2820c715
+gopkg.in/juju/worker.v1 6965b9d826717287bb002e02d1fd4d079978083e
+gopkg.in/macaroon-bakery.v1 469b44e6f1f9479e115c8ae879ef80695be624d5
+gopkg.in/macaroon.v1 ab3940c6c16510a850e1c2dd628b919f0f3f1464
+gopkg.in/mgo.v2 f2b6f6c918c452ad107eec89615f074e3bd80e33
+gopkg.in/natefinch/lumberjack.v2 514cbda263a734ae8caac038dadf05f8f3f9f738
+gopkg.in/natefinch/npipe.v2 c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6
+gopkg.in/retry.v1 c09f6b86ba4d5d2cf5bdf0665364aec9fd4815db
+gopkg.in/tomb.v1 dd632973f1e7218eb1089048e0798ec9ae7dceb8
+gopkg.in/yaml.v2 a3f3340b5840cee44f372bddb5880fcbc419b46a
diff --git a/src/cmd/go/internal/modconv/testdata/juju.tsv b/src/cmd/go/internal/modconv/testdata/juju.tsv
new file mode 100644
index 0000000000..0bddcef81c
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/juju.tsv
@@ -0,0 +1,106 @@
+github.com/Azure/azure-sdk-for-go git 902d95d9f311ae585ee98cfd18f418b467d60d5a 2016-07-20T05:16:58Z
+github.com/Azure/go-autorest git 6f40a8acfe03270d792cb8155e2942c09d7cff95 2016-07-19T23:14:56Z
+github.com/ajstarks/svgo git 89e3ac64b5b3e403a5e7c35ea4f98d45db7b4518 2014-10-04T21:11:59Z
+github.com/altoros/gosigma git 31228935eec685587914528585da4eb9b073c76d 2015-04-08T14:52:32Z
+github.com/beorn7/perks git 3ac7bf7a47d159a033b107610db8a1b6575507a4 2016-02-29T21:34:45Z
+github.com/bmizerany/pat git c068ca2f0aacee5ac3681d68e4d0a003b7d1fd2c 2016-02-17T10:32:42Z
+github.com/coreos/go-systemd git 7b2428fec40033549c68f54e26e89e7ca9a9ce31 2016-02-02T21:14:25Z
+github.com/dgrijalva/jwt-go git 01aeca54ebda6e0fbfafd0a524d234159c05ec20 2016-07-05T20:30:06Z
+github.com/dustin/go-humanize git 145fabdb1ab757076a70a886d092a3af27f66f4c 2014-12-28T07:11:48Z
+github.com/godbus/dbus git 32c6cc29c14570de4cf6d7e7737d68fb2d01ad15 2016-05-06T22:25:50Z
+github.com/golang/protobuf git 4bd1920723d7b7c925de087aa32e2187708897f7 2016-11-09T07:27:36Z
+github.com/google/go-querystring git 9235644dd9e52eeae6fa48efd539fdc351a0af53 2016-04-01T23:30:42Z
+github.com/gorilla/schema git 08023a0215e7fc27a9aecd8b8c50913c40019478 2016-04-26T23:15:12Z
+github.com/gorilla/websocket git 804cb600d06b10672f2fbc0a336a7bee507a428e 2017-02-14T17:41:18Z
+github.com/gosuri/uitable git 36ee7e946282a3fb1cfecd476ddc9b35d8847e42 2016-04-04T20:39:58Z
+github.com/joyent/gocommon git ade826b8b54e81a779ccb29d358a45ba24b7809c 2016-03-20T19:31:33Z
+github.com/joyent/gosdc git 2f11feadd2d9891e92296a1077c3e2e56939547d 2014-05-24T00:08:15Z
+github.com/joyent/gosign git 0da0d5f1342065321c97812b1f4ac0c2b0bab56c 2014-05-24T00:07:34Z
+github.com/juju/ansiterm git b99631de12cf04a906c1d4e4ec54fb86eae5863d 2016-09-07T23:45:32Z
+github.com/juju/blobstore git 06056004b3d7b54bbb7984d830c537bad00fec21 2015-07-29T11:18:58Z
+github.com/juju/bundlechanges git 7725027b95e0d54635e0fb11efc2debdcdf19f75 2016-12-15T16:06:52Z
+github.com/juju/cmd git 9425a576247f348b9b40afe3b60085de63470de5 2017-03-20T01:37:09Z
+github.com/juju/description git d3742c23561884cd7d759ef7142340af1d22cab0 2017-03-20T07:46:40Z
+github.com/juju/errors git 1b5e39b83d1835fa480e0c2ddefb040ee82d58b3 2015-09-16T12:56:42Z
+github.com/juju/gnuflag git 4e76c56581859c14d9d87e1ddbe29e1c0f10195f 2016-08-09T16:52:14Z
+github.com/juju/go4 git 40d72ab9641a2a8c36a9c46a51e28367115c8e59 2016-02-22T16:32:58Z
+github.com/juju/gojsonpointer git afe8b77aa08f272b49e01b82de78510c11f61500 2015-02-04T19:46:29Z
+github.com/juju/gojsonreference git f0d24ac5ee330baa21721cdff56d45e4ee42628e 2015-02-04T19:46:33Z
+github.com/juju/gojsonschema git e1ad140384f254c82f89450d9a7c8dd38a632838 2015-03-12T17:00:16Z
+github.com/juju/gomaasapi git cfbc096bd45f276c17a391efc4db710b60ae3ad7 2017-02-27T07:51:07Z
+github.com/juju/httpprof git 14bf14c307672fd2456bdbf35d19cf0ccd3cf565 2014-12-17T16:00:36Z
+github.com/juju/httprequest git 266fd1e9debf09c037a63f074d099a2da4559ece 2016-10-06T15:09:09Z
+github.com/juju/idmclient git 4dc25171f675da4206b71695d3fd80e519ad05c1 2017-02-09T16:27:49Z
+github.com/juju/jsonschema git a0ef8b74ebcffeeff9fc374854deb4af388f037e 2016-11-02T18:19:19Z
+github.com/juju/loggo git 21bc4c63e8b435779a080e39e592969b7b90b889 2017-02-22T12:20:47Z
+github.com/juju/mempool git 24974d6c264fe5a29716e7d56ea24c4bd904b7cc 2016-02-05T10:49:27Z
+github.com/juju/mutex git 59c26ee163447c5c57f63ff71610d433862013de 2016-06-17T01:09:07Z
+github.com/juju/persistent-cookiejar git 5243747bf8f2d0897f6c7a52799327dc97d585e8 2016-11-15T13:33:28Z
+github.com/juju/pubsub git 9dcaca7eb4340dbf685aa7b3ad4cc4f8691a33d4 2016-07-28T03:00:34Z
+github.com/juju/replicaset git 6b5becf2232ce76656ea765d8d915d41755a1513 2016-11-25T16:08:49Z
+github.com/juju/retry git 62c62032529169c7ec02fa48f93349604c345e1f 2015-10-29T02:48:21Z
+github.com/juju/rfc git ebdbbdb950cd039a531d15cdc2ac2cbd94f068ee 2016-07-11T02:42:13Z
+github.com/juju/romulus git 98d6700423d63971f10ca14afea9ecf2b9b99f0f 2017-01-23T14:29:29Z
+github.com/juju/schema git 075de04f9b7d7580d60a1e12a0b3f50bb18e6998 2016-04-20T04:42:03Z
+github.com/juju/terms-client git 9b925afd677234e4146dde3cb1a11e187cbed64e 2016-08-09T13:19:00Z
+github.com/juju/testing git fce9bc4ebf7a77310c262ac4884e03b778eae06a 2017-02-22T09:01:19Z
+github.com/juju/txn git 28898197906200d603394d8e4ce537436529f1c5 2016-11-16T04:07:55Z
+github.com/juju/usso git 68a59c96c178fbbad65926e7f93db50a2cd14f33 2016-04-01T10:44:24Z
+github.com/juju/utils git 9f8aeb9b09e2d8c769be8317ccfa23f7eec62c26 2017-02-15T08:19:00Z
+github.com/juju/version git 1f41e27e54f21acccf9b2dddae063a782a8a7ceb 2016-10-31T05:19:06Z
+github.com/juju/webbrowser git 54b8c57083b4afb7dc75da7f13e2967b2606a507 2016-03-09T14:36:29Z
+github.com/juju/xml git eb759a627588d35166bc505fceb51b88500e291e 2015-04-13T13:11:21Z
+github.com/juju/zip git f6b1e93fa2e29a1d7d49b566b2b51efb060c982a 2016-02-05T10:52:21Z
+github.com/julienschmidt/httprouter git 77a895ad01ebc98a4dc95d8355bc825ce80a56f6 2015-10-13T22:55:20Z
+github.com/lestrrat/go-jspointer git f4881e611bdbe9fb413a7780721ef8400a1f2341 2016-02-29T02:13:54Z
+github.com/lestrrat/go-jsref git e452c7b5801d1c6494c9e7e0cbc7498c0f88dfd1 2016-06-01T01:32:40Z
+github.com/lestrrat/go-jsschema git b09d7650b822d2ea3dc83d5091a5e2acd8330051 2016-09-03T13:19:57Z
+github.com/lestrrat/go-jsval git b1258a10419fe0693f7b35ad65cd5074bc0ba1e5 2016-10-12T04:57:17Z
+github.com/lestrrat/go-pdebug git 2e6eaaa5717f81bda41d27070d3c966f40a1e75f 2016-08-17T06:33:33Z
+github.com/lestrrat/go-structinfo git f74c056fe41f860aa6264478c664a6fff8a64298 2016-03-08T13:11:05Z
+github.com/lunixbochs/vtclean git 4fbf7632a2c6d3fbdb9931439bdbbeded02cbe36 2016-01-25T03:51:06Z
+github.com/lxc/lxd git 23da0234979fa6299565b91b529a6dbeb42ee36d 2017-02-16T05:29:42Z
+github.com/masterzen/azure-sdk-for-go git ee4f0065d00cd12b542f18f5bc45799e88163b12 2016-10-14T13:56:28Z
+github.com/masterzen/simplexml git 4572e39b1ab9fe03ee513ce6fc7e289e98482190 2016-06-08T18:30:07Z
+github.com/masterzen/winrm git 7a535cd943fccaeed196718896beec3fb51aff41 2016-10-14T15:10:40Z
+github.com/masterzen/xmlpath git 13f4951698adc0fa9c1dda3e275d489a24201161 2014-02-18T18:59:01Z
+github.com/mattn/go-colorable git ed8eb9e318d7a84ce5915b495b7d35e0cfe7b5a8 2016-07-31T23:54:17Z
+github.com/mattn/go-isatty git 66b8e73f3f5cda9f96b69efd03dd3d7fc4a5cdb8 2016-08-06T12:27:52Z
+github.com/mattn/go-runewidth git d96d1bd051f2bd9e7e43d602782b37b93b1b5666 2015-11-18T07:21:59Z
+github.com/matttproud/golang_protobuf_extensions git c12348ce28de40eed0136aa2b644d0ee0650e56c 2016-04-24T11:30:07Z
+github.com/nu7hatch/gouuid git 179d4d0c4d8d407a32af483c2354df1d2c91e6c3 2013-12-21T20:05:32Z
+github.com/pkg/errors git 839d9e913e063e28dfd0e6c7b7512793e0a48be9 2016-10-02T05:25:12Z
+github.com/prometheus/client_golang git 575f371f7862609249a1be4c9145f429fe065e32 2016-11-24T15:57:32Z
+github.com/prometheus/client_model git fa8ad6fec33561be4280a8f0514318c79d7f6cb6 2015-02-12T10:17:44Z
+github.com/prometheus/common git dd586c1c5abb0be59e60f942c22af711a2008cb4 2016-05-03T22:05:32Z
+github.com/prometheus/procfs git abf152e5f3e97f2fafac028d2cc06c1feb87ffa5 2016-04-11T19:08:41Z
+github.com/rogpeppe/fastuuid git 6724a57986aff9bff1a1770e9347036def7c89f6 2015-01-06T09:32:20Z
+github.com/vmware/govmomi git c0c7ce63df7edd78e713257b924c89d9a2dac119 2016-06-30T15:37:42Z
+golang.org/x/crypto git 8e06e8ddd9629eb88639aba897641bff8031f1d3 2016-09-22T17:06:29Z
+golang.org/x/net git ea47fc708ee3e20177f3ca3716217c4ab75942cb 2015-08-29T23:03:18Z
+golang.org/x/oauth2 git 11c60b6f71a6ad48ed6f93c65fa4c6f9b1b5b46a 2015-03-25T02:00:22Z
+golang.org/x/sys git 7a6e5648d140666db5d920909e082ca00a87ba2c 2017-02-01T05:12:45Z
+golang.org/x/text git 2910a502d2bf9e43193af9d68ca516529614eed3 2016-07-26T16:48:57Z
+google.golang.org/api git 0d3983fb069cb6651353fc44c5cb604e263f2a93 2014-12-10T23:51:26Z
+google.golang.org/cloud git f20d6dcccb44ed49de45ae3703312cb46e627db1 2015-03-19T22:36:35Z
+gopkg.in/amz.v3 git 8c3190dff075bf5442c9eedbf8f8ed6144a099e7 2016-12-15T13:08:49Z
+gopkg.in/check.v1 git 4f90aeace3a26ad7021961c297b22c42160c7b25 2016-01-05T16:49:36Z
+gopkg.in/errgo.v1 git 442357a80af5c6bf9b6d51ae791a39c3421004f3 2016-12-22T12:58:16Z
+gopkg.in/goose.v1 git ac43167b647feacdd9a1e34ee81e574551bc748d 2017-02-15T01:56:23Z
+gopkg.in/ini.v1 git 776aa739ce9373377cd16f526cdf06cb4c89b40f 2016-02-22T23:24:41Z
+gopkg.in/juju/blobstore.v2 git 51fa6e26128d74e445c72d3a91af555151cc3654 2016-01-25T02:37:03Z
+gopkg.in/juju/charm.v6-unstable git 83771c4919d6810bce5b7e63f46bea5fbfed0b93 2016-10-03T20:31:18Z
+gopkg.in/juju/charmrepo.v2-unstable git e79aa298df89ea887c9bffec46063c24bfb730f7 2016-11-17T15:25:28Z
+gopkg.in/juju/charmstore.v5-unstable git fd1eef3002fc6b6daff5e97efab6f5056d22dcc7 2016-09-16T10:09:07Z
+gopkg.in/juju/environschema.v1 git 7359fc7857abe2b11b5b3e23811a9c64cb6b01e0 2015-11-04T11:58:10Z
+gopkg.in/juju/jujusvg.v2 git d82160011935ef79fc7aca84aba2c6f74700fe75 2016-06-09T10:52:15Z
+gopkg.in/juju/names.v2 git 0847c26d322a121e52614f969fb82eae2820c715 2016-11-02T13:43:03Z
+gopkg.in/juju/worker.v1 git 6965b9d826717287bb002e02d1fd4d079978083e 2017-03-08T00:24:58Z
+gopkg.in/macaroon-bakery.v1 git 469b44e6f1f9479e115c8ae879ef80695be624d5 2016-06-22T12:14:21Z
+gopkg.in/macaroon.v1 git ab3940c6c16510a850e1c2dd628b919f0f3f1464 2015-01-21T11:42:31Z
+gopkg.in/mgo.v2 git f2b6f6c918c452ad107eec89615f074e3bd80e33 2016-08-18T01:52:18Z
+gopkg.in/natefinch/lumberjack.v2 git 514cbda263a734ae8caac038dadf05f8f3f9f738 2016-01-25T11:17:49Z
+gopkg.in/natefinch/npipe.v2 git c1b8fa8bdccecb0b8db834ee0b92fdbcfa606dd6 2016-06-21T03:49:01Z
+gopkg.in/retry.v1 git c09f6b86ba4d5d2cf5bdf0665364aec9fd4815db 2016-10-25T18:14:30Z
+gopkg.in/tomb.v1 git dd632973f1e7218eb1089048e0798ec9ae7dceb8 2014-10-24T13:56:13Z
+gopkg.in/yaml.v2 git a3f3340b5840cee44f372bddb5880fcbc419b46a 2017-02-08T14:18:51Z
diff --git a/src/cmd/go/internal/modconv/testdata/moby.out b/src/cmd/go/internal/modconv/testdata/moby.out
new file mode 100644
index 0000000000..2cb2e056a8
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/moby.out
@@ -0,0 +1,105 @@
+github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
+github.com/Microsoft/hcsshim v0.6.5
+github.com/Microsoft/go-winio v0.4.5
+github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
+github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
+github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609
+github.com/gorilla/context v1.1
+github.com/gorilla/mux v1.1
+github.com/Microsoft/opengcs v0.3.4
+github.com/kr/pty 5cf931ef8f
+github.com/mattn/go-shellwords v1.0.3
+github.com/sirupsen/logrus v1.0.3
+github.com/tchap/go-patricia v2.2.6
+github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
+golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
+golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
+github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
+github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
+github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
+github.com/pmezard/go-difflib v1.0.0
+github.com/gotestyourself/gotestyourself v1.1.0
+github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
+github.com/imdario/mergo 0.2.1
+golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
+github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8
+github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
+github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
+github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce
+github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
+github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
+github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
+github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
+github.com/hashicorp/memberlist v0.1.0
+github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
+github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
+github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
+github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
+github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
+github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
+github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
+github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
+github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
+github.com/coreos/etcd v3.2.1
+github.com/coreos/go-semver v0.2.0
+github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
+github.com/hashicorp/consul v0.5.2
+github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
+github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
+github.com/vbatts/tar-split v0.10.1
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
+github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
+github.com/pborman/uuid v1.0
+google.golang.org/grpc v1.3.0
+github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
+github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
+github.com/opencontainers/runtime-spec v1.0.0
+github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
+github.com/coreos/go-systemd v4
+github.com/godbus/dbus v4.0.0
+github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
+github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
+github.com/Graylog2/go-gelf v2
+github.com/fluent/fluent-logger-golang v1.2.1
+github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972
+github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
+github.com/fsnotify/fsnotify v1.4.2
+github.com/aws/aws-sdk-go v1.4.22
+github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0
+github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
+github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
+golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
+google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
+cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
+github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
+google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
+github.com/containerd/containerd 06b9cb35161009dcb7123345749fef02f7cea8e0
+github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
+github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0
+github.com/gogo/protobuf v0.4
+github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
+github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
+golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
+golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
+github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
+github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990
+github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
+github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
+github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
+github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/matttproud/golang_protobuf_extensions v1.0.0
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
+github.com/spf13/cobra v1.5.1
+github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c
+github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
+github.com/opencontainers/selinux v1.0.0-rc1
diff --git a/src/cmd/go/internal/modconv/testdata/moby.vconf b/src/cmd/go/internal/modconv/testdata/moby.vconf
new file mode 100644
index 0000000000..53b90d1e37
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/moby.vconf
@@ -0,0 +1,149 @@
+# the following lines are in sorted order, FYI
+github.com/Azure/go-ansiterm d6e3b3328b783f23731bc4d058875b0371ff8109
+github.com/Microsoft/hcsshim v0.6.5
+github.com/Microsoft/go-winio v0.4.5
+github.com/davecgh/go-spew 346938d642f2ec3594ed81d874461961cd0faa76
+github.com/docker/libtrust 9cbd2a1374f46905c68a4eb3694a130610adc62a
+github.com/go-check/check 4ed411733c5785b40214c70bce814c3a3a689609 https://github.com/cpuguy83/check.git
+github.com/gorilla/context v1.1
+github.com/gorilla/mux v1.1
+github.com/Microsoft/opengcs v0.3.4
+github.com/kr/pty 5cf931ef8f
+github.com/mattn/go-shellwords v1.0.3
+github.com/sirupsen/logrus v1.0.3
+github.com/tchap/go-patricia v2.2.6
+github.com/vdemeester/shakers 24d7f1d6a71aa5d9cbe7390e4afb66b7eef9e1b3
+golang.org/x/net 7dcfb8076726a3fdd9353b6b8a1f1b6be6811bd6
+golang.org/x/sys 07c182904dbd53199946ba614a412c61d3c548f5
+github.com/docker/go-units 9e638d38cf6977a37a8ea0078f3ee75a7cdb2dd1
+github.com/docker/go-connections 3ede32e2033de7505e6500d6c868c2b9ed9f169d
+golang.org/x/text f72d8390a633d5dfb0cc84043294db9f6c935756
+github.com/stretchr/testify 4d4bfba8f1d1027c4fdbe371823030df51419987
+github.com/pmezard/go-difflib v1.0.0
+github.com/gotestyourself/gotestyourself v1.1.0
+
+github.com/RackSec/srslog 456df3a81436d29ba874f3590eeeee25d666f8a5
+github.com/imdario/mergo 0.2.1
+golang.org/x/sync de49d9dcd27d4f764488181bea099dfe6179bcf0
+
+github.com/containerd/continuity 22694c680ee48fb8f50015b44618517e2bde77e8
+github.com/moby/buildkit aaff9d591ef128560018433fe61beb802e149de8
+github.com/tonistiigi/fsutil dea3a0da73aee887fc02142d995be764106ac5e2
+
+#get libnetwork packages
+github.com/docker/libnetwork 68f1039f172434709a4550fe92e3e058406c74ce
+github.com/docker/go-events 9461782956ad83b30282bf90e31fa6a70c255ba9
+github.com/armon/go-radix e39d623f12e8e41c7b5529e9a9dd67a1e2261f80
+github.com/armon/go-metrics eb0af217e5e9747e41dd5303755356b62d28e3ec
+github.com/hashicorp/go-msgpack 71c2886f5a673a35f909803f38ece5810165097b
+github.com/hashicorp/memberlist v0.1.0
+github.com/sean-/seed e2103e2c35297fb7e17febb81e49b312087a2372
+github.com/hashicorp/go-sockaddr acd314c5781ea706c710d9ea70069fd2e110d61d
+github.com/hashicorp/go-multierror fcdddc395df1ddf4247c69bd436e84cfa0733f7e
+github.com/hashicorp/serf 598c54895cc5a7b1a24a398d635e8c0ea0959870
+github.com/docker/libkv 1d8431073ae03cdaedb198a89722f3aab6d418ef
+github.com/vishvananda/netns 604eaf189ee867d8c147fafc28def2394e878d25
+github.com/vishvananda/netlink bd6d5de5ccef2d66b0a26177928d0d8895d7f969
+github.com/BurntSushi/toml f706d00e3de6abe700c994cdd545a1a4915af060
+github.com/samuel/go-zookeeper d0e0d8e11f318e000a8cc434616d69e329edc374
+github.com/deckarep/golang-set ef32fa3046d9f249d399f98ebaf9be944430fd1d
+github.com/coreos/etcd v3.2.1
+github.com/coreos/go-semver v0.2.0
+github.com/ugorji/go f1f1a805ed361a0e078bb537e4ea78cd37dcf065
+github.com/hashicorp/consul v0.5.2
+github.com/boltdb/bolt fff57c100f4dea1905678da7e90d92429dff2904
+github.com/miekg/dns 75e6e86cc601825c5dbcd4e0c209eab180997cd7
+
+# get graph and distribution packages
+github.com/docker/distribution edc3ab29cdff8694dd6feb85cfeb4b5f1b38ed9c
+github.com/vbatts/tar-split v0.10.1
+github.com/opencontainers/go-digest a6d0ee40d4207ea02364bd3b9e8e77b9159ba1eb
+
+# get go-zfs packages
+github.com/mistifyio/go-zfs 22c9b32c84eb0d0c6f4043b6e90fc94073de92fa
+github.com/pborman/uuid v1.0
+
+google.golang.org/grpc v1.3.0
+
+# When updating, also update RUNC_COMMIT in hack/dockerfile/binaries-commits accordingly
+github.com/opencontainers/runc 0351df1c5a66838d0c392b4ac4cf9450de844e2d
+github.com/opencontainers/image-spec 372ad780f63454fbbbbcc7cf80e5b90245c13e13
+github.com/opencontainers/runtime-spec v1.0.0
+
+github.com/seccomp/libseccomp-golang 32f571b70023028bd57d9288c20efbcb237f3ce0
+
+# libcontainer deps (see src/github.com/opencontainers/runc/Godeps/Godeps.json)
+github.com/coreos/go-systemd v4
+github.com/godbus/dbus v4.0.0
+github.com/syndtr/gocapability 2c00daeb6c3b45114c80ac44119e7b8801fdd852
+github.com/golang/protobuf 7a211bcf3bce0e3f1d74f9894916e6f116ae83b4
+
+# gelf logging driver deps
+github.com/Graylog2/go-gelf v2
+
+github.com/fluent/fluent-logger-golang v1.2.1
+# fluent-logger-golang deps
+github.com/philhofer/fwd 98c11a7a6ec829d672b03833c3d69a7fae1ca972
+github.com/tinylib/msgp 75ee40d2601edf122ef667e2a07d600d4c44490c
+
+# fsnotify
+github.com/fsnotify/fsnotify v1.4.2
+
+# awslogs deps
+github.com/aws/aws-sdk-go v1.4.22
+github.com/go-ini/ini 060d7da055ba6ec5ea7a31f116332fe5efa04ce0
+github.com/jmespath/go-jmespath 0b12d6b521d83fc7f755e7cfc1b1fbdd35a01a74
+
+# logentries
+github.com/bsphere/le_go 7a984a84b5492ae539b79b62fb4a10afc63c7bcf
+
+# gcplogs deps
+golang.org/x/oauth2 96382aa079b72d8c014eb0c50f6c223d1e6a2de0
+google.golang.org/api 3cc2e591b550923a2c5f0ab5a803feda924d5823
+cloud.google.com/go 9d965e63e8cceb1b5d7977a202f0fcb8866d6525
+github.com/googleapis/gax-go da06d194a00e19ce00d9011a13931c3f6f6887c7
+google.golang.org/genproto d80a6e20e776b0b17a324d0ba1ab50a39c8e8944
+
+# containerd
+github.com/containerd/containerd 06b9cb35161009dcb7123345749fef02f7cea8e0
+github.com/tonistiigi/fifo 1405643975692217d6720f8b54aeee1bf2cd5cf4
+
+# cluster
+github.com/docker/swarmkit 872861d2ae46958af7ead1d5fffb092c73afbaf0
+github.com/gogo/protobuf v0.4
+github.com/cloudflare/cfssl 7fb22c8cba7ecaf98e4082d22d65800cf45e042a
+github.com/google/certificate-transparency d90e65c3a07988180c5b1ece71791c0b6506826e
+golang.org/x/crypto 558b6879de74bc843225cde5686419267ff707ca
+golang.org/x/time a4bde12657593d5e90d0533a3e4fd95e635124cb
+github.com/hashicorp/go-memdb cb9a474f84cc5e41b273b20c6927680b2a8776ad
+github.com/hashicorp/go-immutable-radix 8e8ed81f8f0bf1bdd829593fdd5c29922c1ea990
+github.com/hashicorp/golang-lru a0d98a5f288019575c6d1f4bb1573fef2d1fcdc4
+github.com/coreos/pkg fa29b1d70f0beaddd4c7021607cc3c3be8ce94b8
+github.com/pivotal-golang/clock 3fd3c1944c59d9742e1cd333672181cd1a6f9fa0
+github.com/prometheus/client_golang 52437c81da6b127a9925d17eb3a382a2e5fd395e
+github.com/beorn7/perks 4c0e84591b9aa9e6dcfdf3e020114cd81f89d5f9
+github.com/prometheus/client_model fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common ebdfc6da46522d58825777cf1f90490a5b1ef1d8
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/matttproud/golang_protobuf_extensions v1.0.0
+github.com/pkg/errors 839d9e913e063e28dfd0e6c7b7512793e0a48be9
+github.com/grpc-ecosystem/go-grpc-prometheus 6b7015e65d366bf3f19b2b2a000a831940f0f7e0
+
+# cli
+github.com/spf13/cobra v1.5.1 https://github.com/dnephin/cobra.git
+github.com/spf13/pflag 9ff6c6923cfffbcd502984b8e0c80539a94968b7
+github.com/inconshreveable/mousetrap 76626ae9c91c4f2a10f34cad8ce83ea42c93bb75
+github.com/Nvveen/Gotty a8b993ba6abdb0e0c12b0125c603323a71c7790c https://github.com/ijc25/Gotty
+
+# metrics
+github.com/docker/go-metrics d466d4f6fd960e01820085bd7e1a24426ee7ef18
+
+github.com/opencontainers/selinux v1.0.0-rc1
+
+# archive/tar
+# mkdir -p ./vendor/archive
+# git clone git://github.com/tonistiigi/go-1.git ./go
+# git --git-dir ./go/.git --work-tree ./go checkout revert-prefix-ignore
+# cp -a go/src/archive/tar ./vendor/archive/tar
+# rm -rf ./go
+# vndr
diff --git a/src/cmd/go/internal/modconv/testdata/panicparse.out b/src/cmd/go/internal/modconv/testdata/panicparse.out
new file mode 100644
index 0000000000..8830033c6b
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/panicparse.out
@@ -0,0 +1,8 @@
+github.com/kr/pretty 737b74a46c4bf788349f72cb256fed10aea4d0ac
+github.com/kr/text 7cafcd837844e784b526369c9bce262804aebc60
+github.com/maruel/ut a9c9f15ccfa6f8b90182a53df32f4745586fbae3
+github.com/mattn/go-colorable 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59
+github.com/mattn/go-isatty 56b76bdf51f7708750eac80fa38b952bb9f32639
+github.com/mgutz/ansi c286dcecd19ff979eeb73ea444e479b903f2cfcb
+github.com/pmezard/go-difflib 792786c7400a136282c1664665ae0a8db921c6c2
+golang.org/x/sys a646d33e2ee3172a661fc09bca23bb4889a41bc8
diff --git a/src/cmd/go/internal/modconv/testdata/panicparse.vyml b/src/cmd/go/internal/modconv/testdata/panicparse.vyml
new file mode 100644
index 0000000000..ff3d43f5f2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/panicparse.vyml
@@ -0,0 +1,17 @@
+vendors:
+- path: github.com/kr/pretty
+ rev: 737b74a46c4bf788349f72cb256fed10aea4d0ac
+- path: github.com/kr/text
+ rev: 7cafcd837844e784b526369c9bce262804aebc60
+- path: github.com/maruel/ut
+ rev: a9c9f15ccfa6f8b90182a53df32f4745586fbae3
+- path: github.com/mattn/go-colorable
+ rev: 9056b7a9f2d1f2d96498d6d146acd1f9d5ed3d59
+- path: github.com/mattn/go-isatty
+ rev: 56b76bdf51f7708750eac80fa38b952bb9f32639
+- path: github.com/mgutz/ansi
+ rev: c286dcecd19ff979eeb73ea444e479b903f2cfcb
+- path: github.com/pmezard/go-difflib
+ rev: 792786c7400a136282c1664665ae0a8db921c6c2
+- path: golang.org/x/sys
+ rev: a646d33e2ee3172a661fc09bca23bb4889a41bc8
diff --git a/src/cmd/go/internal/modconv/testdata/prometheus.out b/src/cmd/go/internal/modconv/testdata/prometheus.out
new file mode 100644
index 0000000000..d11b8ecc72
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/prometheus.out
@@ -0,0 +1,258 @@
+cloud.google.com/go/compute/metadata c589d0c9f0d81640c518354c7bcae77d99820aa3
+cloud.google.com/go/internal c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/Azure/azure-sdk-for-go/arm/compute bd73d950fa4440dae889bd9917bff7cef539f86e
+github.com/Azure/azure-sdk-for-go/arm/network bd73d950fa4440dae889bd9917bff7cef539f86e
+github.com/Azure/go-autorest/autorest 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/azure 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/date 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/to 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/Azure/go-autorest/autorest/validation 8a25372bbfec739b8719a9e3987400d15ef9e179
+github.com/PuerkitoBio/purell c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/PuerkitoBio/urlesc c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/asaskevich/govalidator 7b3beb6df3c42abd3509abfc3bcacc0fbfb7c877
+github.com/aws/aws-sdk-go/aws 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/awserr 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/awsutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/client 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/client/metadata 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/corehandlers 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/endpointcreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/credentials/stscreds 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/defaults 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/ec2metadata 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/request 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/session 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/aws/signer/v4 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/endpoints 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/ec2query 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/query 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/query/queryutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/rest 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/private/waiter 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/service/ec2 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/aws/aws-sdk-go/service/sts 707203bc55114ed114446bf57949c5c211d8b7c0
+github.com/beorn7/perks/quantile 3ac7bf7a47d159a033b107610db8a1b6575507a4
+github.com/blang/semver c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/http c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/jose c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/key c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/oauth2 c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/go-oidc/oidc c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/health c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/httputil c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/coreos/pkg/timeutil c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/davecgh/go-spew/spew c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/dgrijalva/jwt-go 9ed569b5d1ac936e6494082958d63a6aa4fff99a
+github.com/docker/distribution/digest c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/docker/distribution/reference c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful/log c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/emicklei/go-restful/swagger c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/ghodss/yaml c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-ini/ini 6e4869b434bd001f6983749881c7ead3545887d8
+github.com/go-openapi/jsonpointer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/jsonreference c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/spec c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/go-openapi/swag c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/gogo/protobuf/proto c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/gogo/protobuf/sortkeys c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/golang/glog c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/golang/protobuf/proto 98fa357170587e470c5f27d3c3ea0947b71eb455
+github.com/golang/snappy d9eb7a3d35ec988b8585d4a0068e462c27d28380
+github.com/google/gofuzz c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/hashicorp/consul/api daacc4be8bee214e3fc4b32a6dd385f5ef1b4c36
+github.com/hashicorp/go-cleanhttp ad28ea4487f05916463e2423a55166280e8254b5
+github.com/hashicorp/serf/coordinate 1d4fa605f6ff3ed628d7ae5eda7c0e56803e72a5
+github.com/influxdb/influxdb/client 291aaeb9485b43b16875c238482b2f7d0a22a13b
+github.com/influxdb/influxdb/tsdb 291aaeb9485b43b16875c238482b2f7d0a22a13b
+github.com/jmespath/go-jmespath bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d
+github.com/jonboulle/clockwork c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/juju/ratelimit c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/julienschmidt/httprouter 109e267447e95ad1bb48b758e40dd7453eb7b039
+github.com/mailru/easyjson/buffer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/mailru/easyjson/jlexer c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/mailru/easyjson/jwriter c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/matttproud/golang_protobuf_extensions/pbutil fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a
+github.com/miekg/dns 58f52c57ce9df13460ac68200cef30a008b9c468
+github.com/pborman/uuid c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/pmezard/go-difflib/difflib d77da356e56a7428ad25149ca77381849a6a5232
+github.com/prometheus/client_golang/prometheus c5b7fccd204277076155f10851dad72b76a49317
+github.com/prometheus/client_model/go fa8ad6fec33561be4280a8f0514318c79d7f6cb6
+github.com/prometheus/common/expfmt 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/log 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/model 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/route 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/common/version 85637ea67b04b5c3bb25e671dacded2977f8f9f6
+github.com/prometheus/procfs abf152e5f3e97f2fafac028d2cc06c1feb87ffa5
+github.com/samuel/go-zookeeper/zk 177002e16a0061912f02377e2dd8951a8b3551bc
+github.com/spf13/pflag c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/stretchr/testify/assert d77da356e56a7428ad25149ca77381849a6a5232
+github.com/stretchr/testify/require d77da356e56a7428ad25149ca77381849a6a5232
+github.com/syndtr/goleveldb/leveldb 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/cache 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/comparer 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/errors 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/filter 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/iterator 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/journal 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/memdb 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/opt 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/storage 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/table 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/syndtr/goleveldb/leveldb/util 6b4daa5362b502898ddf367c5c11deb9e7a5c727
+github.com/ugorji/go/codec c589d0c9f0d81640c518354c7bcae77d99820aa3
+github.com/vaughan0/go-ini a98ad7ee00ec53921f08832bc06ecf7fd600e6a1
+golang.org/x/net/context b336a971b799939dd16ae9b1df8334cb8b977c4d
+golang.org/x/net/context/ctxhttp b336a971b799939dd16ae9b1df8334cb8b977c4d
+golang.org/x/net/http2 c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/http2/hpack c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/idna c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/internal/timeseries 6250b412798208e6c90b03b7c4f226de5aa299e2
+golang.org/x/net/lex/httplex c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/net/netutil bc3663df0ac92f928d419e31e0d2af22e683a5a2
+golang.org/x/oauth2 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/google 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/internal 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/jws 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/oauth2/jwt 65a8d08c6292395d47053be10b3c5e91960def76
+golang.org/x/sys/unix c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows/registry c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/sys/windows/svc/eventlog c200b10b5d5e122be351b67af224adc6128af5bf
+golang.org/x/text/cases c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/internal/tag c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/language c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/runes c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/secure/bidirule c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/secure/precis c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/transform c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/unicode/bidi c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/unicode/norm c589d0c9f0d81640c518354c7bcae77d99820aa3
+golang.org/x/text/width c589d0c9f0d81640c518354c7bcae77d99820aa3
+google.golang.org/api/compute/v1 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/gensupport 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/googleapi 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/api/googleapi/internal/uritemplates 63ade871fd3aec1225809d496e81ec91ab76ea29
+google.golang.org/appengine 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/app_identity 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/base 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/datastore 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/log 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/modules 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/internal/remote_api 4f7eeb5305a4ba1966344836ba4af9996b7b4e05
+google.golang.org/appengine/internal/urlfetch 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/appengine/urlfetch 267c27e7492265b84fc6719503b14a1e17975d79
+google.golang.org/cloud/compute/metadata 0a83eba2cadb60eb22123673c8fb6fca02b03c94
+google.golang.org/cloud/internal 0a83eba2cadb60eb22123673c8fb6fca02b03c94
+gopkg.in/fsnotify.v1 30411dbcefb7a1da7e84f75530ad3abe4011b4f8
+gopkg.in/inf.v0 c589d0c9f0d81640c518354c7bcae77d99820aa3
+gopkg.in/yaml.v2 7ad95dd0798a40da1ccdff6dff35fd177b5edf40
+k8s.io/client-go/1.5/discovery c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/apps/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/authentication/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/authorization/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/autoscaling/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/batch/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/certificates/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/core/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/extensions/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/policy/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/rbac/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/kubernetes/typed/storage/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/errors c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/meta c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/meta/metatypes c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/resource c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/unversioned c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/api/validation/path c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery/announced c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apimachinery/registered c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/apps/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authentication/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/authorization/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/autoscaling/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/v1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/batch/v2alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/certificates/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/policy/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/rbac/v1alpha1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage/install c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/apis/storage/v1beta1 c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/auth/user c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/conversion c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/conversion/queryparams c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/fields c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/genericapiserver/openapi/common c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/labels c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/json c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/protobuf c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/recognizer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/streaming c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/runtime/serializer/versioning c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/selection c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/third_party/forked/golang/reflect c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/types c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/cert c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/clock c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/errors c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/flowcontrol c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/framer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/integer c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/intstr c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/json c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/labels c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/net c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/parsers c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/rand c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/runtime c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/sets c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/uuid c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/validation c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/validation/field c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/wait c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/util/yaml c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/version c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/watch c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/pkg/watch/versioned c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth/gcp c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/plugin/pkg/client/auth/oidc c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/rest c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/cache c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/clientcmd/api c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/tools/metrics c589d0c9f0d81640c518354c7bcae77d99820aa3
+k8s.io/client-go/1.5/transport c589d0c9f0d81640c518354c7bcae77d99820aa3
diff --git a/src/cmd/go/internal/modconv/testdata/prometheus.vjson b/src/cmd/go/internal/modconv/testdata/prometheus.vjson
new file mode 100644
index 0000000000..648bec4260
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/prometheus.vjson
@@ -0,0 +1,1605 @@
+{
+ "comment": "",
+ "ignore": "test appengine",
+ "package": [
+ {
+ "checksumSHA1": "Cslv4/ITyQmgjSUhNXFu8q5bqOU=",
+ "origin": "k8s.io/client-go/1.5/vendor/cloud.google.com/go/compute/metadata",
+ "path": "cloud.google.com/go/compute/metadata",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hiJXjkFEGy+sDFf6O58Ocdy9Rnk=",
+ "origin": "k8s.io/client-go/1.5/vendor/cloud.google.com/go/internal",
+ "path": "cloud.google.com/go/internal",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "oIt4tXgFYnZJBsCac1BQLnTWALM=",
+ "path": "github.com/Azure/azure-sdk-for-go/arm/compute",
+ "revision": "bd73d950fa4440dae889bd9917bff7cef539f86e",
+ "revisionTime": "2016-10-28T18:31:11Z"
+ },
+ {
+ "checksumSHA1": "QKi6LiSyD5GnRK8ExpMgZl4XiMI=",
+ "path": "github.com/Azure/azure-sdk-for-go/arm/network",
+ "revision": "bd73d950fa4440dae889bd9917bff7cef539f86e",
+ "revisionTime": "2016-10-28T18:31:11Z"
+ },
+ {
+ "checksumSHA1": "eVSHe6GIHj9/ziFrQLZ1SC7Nn6k=",
+ "path": "github.com/Azure/go-autorest/autorest",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "0sYi0JprevG/PZjtMbOh8h0pt0g=",
+ "path": "github.com/Azure/go-autorest/autorest/azure",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "q9Qz8PAxK5FTOZwgYKe5Lj38u4c=",
+ "path": "github.com/Azure/go-autorest/autorest/date",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "Ev8qCsbFjDlMlX0N2tYAhYQFpUc=",
+ "path": "github.com/Azure/go-autorest/autorest/to",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "oBixceM+55gdk47iff8DSEIh3po=",
+ "path": "github.com/Azure/go-autorest/autorest/validation",
+ "revision": "8a25372bbfec739b8719a9e3987400d15ef9e179",
+ "revisionTime": "2016-10-25T18:07:34Z"
+ },
+ {
+ "checksumSHA1": "IatnluZB5jTVUncMN134e4VOV34=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/PuerkitoBio/purell",
+ "path": "github.com/PuerkitoBio/purell",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "E/Tz8z0B/gaR551g+XqPKAhcteM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/PuerkitoBio/urlesc",
+ "path": "github.com/PuerkitoBio/urlesc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BdLdZP/C2uOO3lqk9X3NCKFpXa4=",
+ "path": "github.com/asaskevich/govalidator",
+ "revision": "7b3beb6df3c42abd3509abfc3bcacc0fbfb7c877",
+ "revisionTime": "2016-10-01T16:31:30Z"
+ },
+ {
+ "checksumSHA1": "WNfR3yhLjRC5/uccgju/bwrdsxQ=",
+ "path": "github.com/aws/aws-sdk-go/aws",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Y9W+4GimK4Fuxq+vyIskVYFRnX4=",
+ "path": "github.com/aws/aws-sdk-go/aws/awserr",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "+q4vdl3l1Wom8K1wfIpJ4jlFsbY=",
+ "path": "github.com/aws/aws-sdk-go/aws/awsutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "/232RBWA3KnT7U+wciPS2+wmvR0=",
+ "path": "github.com/aws/aws-sdk-go/aws/client",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ieAJ+Cvp/PKv1LpUEnUXpc3OI6E=",
+ "path": "github.com/aws/aws-sdk-go/aws/client/metadata",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "c1N3Loy3AS9zD+m5CzpPNAED39U=",
+ "path": "github.com/aws/aws-sdk-go/aws/corehandlers",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "zu5C95rmCZff6NYZb62lEaT5ibE=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "KQiUK/zr3mqnAXD7x/X55/iNme0=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/ec2rolecreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "NUJUTWlc1sV8b7WjfiYc4JZbXl0=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/endpointcreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "4Ipx+5xN0gso+cENC2MHMWmQlR4=",
+ "path": "github.com/aws/aws-sdk-go/aws/credentials/stscreds",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "DwhFsNluCFEwqzyp3hbJR3q2Wqs=",
+ "path": "github.com/aws/aws-sdk-go/aws/defaults",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "8E0fEBUJY/1lJOyVxzTxMGQGInk=",
+ "path": "github.com/aws/aws-sdk-go/aws/ec2metadata",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "5Ac22YMTBmrX/CXaEIXzWljr8UY=",
+ "path": "github.com/aws/aws-sdk-go/aws/request",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "eOo6evLMAxQfo7Qkc5/h5euN1Sw=",
+ "path": "github.com/aws/aws-sdk-go/aws/session",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "diXvBs1LRC0RJ9WK6sllWKdzC04=",
+ "path": "github.com/aws/aws-sdk-go/aws/signer/v4",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Esab5F8KswqkTdB4TtjSvZgs56k=",
+ "path": "github.com/aws/aws-sdk-go/private/endpoints",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "wk7EyvDaHwb5qqoOP/4d3cV0708=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "1QmQ3FqV37w0Zi44qv8pA1GeR0A=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/ec2query",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ZqY5RWavBLWTo6j9xqdyBEaNFRk=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/query",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "5xzix1R8prUyWxgLnzUQoxTsfik=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/query/queryutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "TW/7U+/8ormL7acf6z2rv2hDD+s=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/rest",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "eUEkjyMPAuekKBE4ou+nM9tXEas=",
+ "path": "github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "Eo9yODN5U99BK0pMzoqnBm7PCrY=",
+ "path": "github.com/aws/aws-sdk-go/private/waiter",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "6h4tJ9wVtbYb9wG4srtUxyPoAYM=",
+ "path": "github.com/aws/aws-sdk-go/service/ec2",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "ouwhxcAsIYQ6oJbMRdLW/Ys/iyg=",
+ "path": "github.com/aws/aws-sdk-go/service/sts",
+ "revision": "707203bc55114ed114446bf57949c5c211d8b7c0",
+ "revisionTime": "2016-11-02T21:59:28Z"
+ },
+ {
+ "checksumSHA1": "4QnLdmB1kG3N+KlDd1N+G9TWAGQ=",
+ "path": "github.com/beorn7/perks/quantile",
+ "revision": "3ac7bf7a47d159a033b107610db8a1b6575507a4",
+ "revisionTime": "2016-02-29T21:34:45Z"
+ },
+ {
+ "checksumSHA1": "n+s4YwtzpMWW5Rt0dEaQa7NHDGQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/blang/semver",
+ "path": "github.com/blang/semver",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Z2AOGSmDKKvI6nuxa+UPjQWpIeM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/http",
+ "path": "github.com/coreos/go-oidc/http",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "8yvt1xKCgNwuuavJdxRnvaIjrIc=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/jose",
+ "path": "github.com/coreos/go-oidc/jose",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zhXKrWBSSJLqZxVE/Xsw0M9ynFQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/key",
+ "path": "github.com/coreos/go-oidc/key",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "bkW0mnXvmHQwHprW/6wrbpP7lAk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/oauth2",
+ "path": "github.com/coreos/go-oidc/oauth2",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "E1x2k5FdhJ+dzFrh3kCmC6aJfVw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/go-oidc/oidc",
+ "path": "github.com/coreos/go-oidc/oidc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "O0UMBRCOD9ItMayDqLQ2MJEjkVE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/health",
+ "path": "github.com/coreos/pkg/health",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "74vyZz/d49FZXMbFaHOfCGvSLj0=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/httputil",
+ "path": "github.com/coreos/pkg/httputil",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "etBdQ0LN6ojGunfvUt6B5C3FNrQ=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/coreos/pkg/timeutil",
+ "path": "github.com/coreos/pkg/timeutil",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "SdSd7pyjONWWTHc5XE3AhglLo34=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/davecgh/go-spew/spew",
+ "path": "github.com/davecgh/go-spew/spew",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "2Fy1Y6Z3lRRX1891WF/+HT4XS2I=",
+ "path": "github.com/dgrijalva/jwt-go",
+ "revision": "9ed569b5d1ac936e6494082958d63a6aa4fff99a",
+ "revisionTime": "2016-11-01T19:39:35Z"
+ },
+ {
+ "checksumSHA1": "f1wARLDzsF/JoyN01yoxXEwFIp8=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/docker/distribution/digest",
+ "path": "github.com/docker/distribution/digest",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "PzXRTLmmqWXxmDqdIXLcRYBma18=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/docker/distribution/reference",
+ "path": "github.com/docker/distribution/reference",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "1vQR+ZyudsjKio6RNKmWhwzGTb0=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful",
+ "path": "github.com/emicklei/go-restful",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3xWz4fZ9xW+CfADpYoPFcZCYJ4E=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful/log",
+ "path": "github.com/emicklei/go-restful/log",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "J7CtF9gIs2yH9A7lPQDDrhYxiRk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/emicklei/go-restful/swagger",
+ "path": "github.com/emicklei/go-restful/swagger",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ww7LVo7jNJ1o6sfRcromEHKyY+o=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/ghodss/yaml",
+ "path": "github.com/ghodss/yaml",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "cVyhKIRI2gQrgpn5qrBeAqErmWM=",
+ "path": "github.com/go-ini/ini",
+ "revision": "6e4869b434bd001f6983749881c7ead3545887d8",
+ "revisionTime": "2016-08-27T06:11:18Z"
+ },
+ {
+ "checksumSHA1": "NaZnW0tKj/b0k5WzcMD0twrLbrE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/jsonpointer",
+ "path": "github.com/go-openapi/jsonpointer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3LJXjMDxPY+veIqzQtiAvK3hXnY=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/jsonreference",
+ "path": "github.com/go-openapi/jsonreference",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "faeB3fny260hQ/gEfEXa1ZQTGtk=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/spec",
+ "path": "github.com/go-openapi/spec",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wGpZwJ5HZtReou8A3WEV1Gdxs6k=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/go-openapi/swag",
+ "path": "github.com/go-openapi/swag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BIyZQL97iG7mzZ2UMR3XpiXbZdc=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/gogo/protobuf/proto",
+ "path": "github.com/gogo/protobuf/proto",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "e6cMbpJj41MpihS5eP4SIliRBK4=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/gogo/protobuf/sortkeys",
+ "path": "github.com/gogo/protobuf/sortkeys",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "URsJa4y/sUUw/STmbeYx9EKqaYE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/golang/glog",
+ "path": "github.com/golang/glog",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yDh5kmmr0zEF1r+rvYqbZcR7iLs=",
+ "path": "github.com/golang/protobuf/proto",
+ "revision": "98fa357170587e470c5f27d3c3ea0947b71eb455",
+ "revisionTime": "2016-10-12T20:53:35Z"
+ },
+ {
+ "checksumSHA1": "2a/SsTUBMKtcM6VtpbdPGO+c6c8=",
+ "path": "github.com/golang/snappy",
+ "revision": "d9eb7a3d35ec988b8585d4a0068e462c27d28380",
+ "revisionTime": "2016-05-29T05:00:41Z"
+ },
+ {
+ "checksumSHA1": "/yFfUp3tGt6cK22UVzbq8SjPDCU=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/google/gofuzz",
+ "path": "github.com/google/gofuzz",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "LclVLJYrBi03PBjsVPpgoMbUDQ8=",
+ "path": "github.com/hashicorp/consul/api",
+ "revision": "daacc4be8bee214e3fc4b32a6dd385f5ef1b4c36",
+ "revisionTime": "2016-10-28T04:06:46Z"
+ },
+ {
+ "checksumSHA1": "Uzyon2091lmwacNsl1hCytjhHtg=",
+ "path": "github.com/hashicorp/go-cleanhttp",
+ "revision": "ad28ea4487f05916463e2423a55166280e8254b5",
+ "revisionTime": "2016-04-07T17:41:26Z"
+ },
+ {
+ "checksumSHA1": "E3Xcanc9ouQwL+CZGOUyA/+giLg=",
+ "path": "github.com/hashicorp/serf/coordinate",
+ "revision": "1d4fa605f6ff3ed628d7ae5eda7c0e56803e72a5",
+ "revisionTime": "2016-10-07T00:41:22Z"
+ },
+ {
+ "path": "github.com/influxdb/influxdb/client",
+ "revision": "291aaeb9485b43b16875c238482b2f7d0a22a13b",
+ "revisionTime": "2015-09-16T14:41:53+02:00"
+ },
+ {
+ "path": "github.com/influxdb/influxdb/tsdb",
+ "revision": "291aaeb9485b43b16875c238482b2f7d0a22a13b",
+ "revisionTime": "2015-09-16T14:41:53+02:00"
+ },
+ {
+ "checksumSHA1": "0ZrwvB6KoGPj2PoDNSEJwxQ6Mog=",
+ "path": "github.com/jmespath/go-jmespath",
+ "revision": "bd40a432e4c76585ef6b72d3fd96fb9b6dc7b68d",
+ "revisionTime": "2016-08-03T19:07:31Z"
+ },
+ {
+ "checksumSHA1": "9ZVOEbIXnTuYpVqce4en8rwlkPE=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/jonboulle/clockwork",
+ "path": "github.com/jonboulle/clockwork",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "gA95N2LM2hEJLoqrTPaFsSWDJ2Y=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/juju/ratelimit",
+ "path": "github.com/juju/ratelimit",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Farach1xcmsQYrhiUfkwF2rbIaE=",
+ "path": "github.com/julienschmidt/httprouter",
+ "revision": "109e267447e95ad1bb48b758e40dd7453eb7b039",
+ "revisionTime": "2015-09-05T19:25:33+02:00"
+ },
+ {
+ "checksumSHA1": "urY45++NYCue4nh4k8OjUFnIGfU=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/buffer",
+ "path": "github.com/mailru/easyjson/buffer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yTDKAM4KBgOvXRsZC50zg0OChvM=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/jlexer",
+ "path": "github.com/mailru/easyjson/jlexer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4+d+6rhM1pei6lBguhqSEW7LaXs=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/mailru/easyjson/jwriter",
+ "path": "github.com/mailru/easyjson/jwriter",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Q2vw4HZBbnU8BLFt8VrzStwqSJg=",
+ "path": "github.com/matttproud/golang_protobuf_extensions/pbutil",
+ "revision": "fc2b8d3a73c4867e51861bbdd5ae3c1f0869dd6a",
+ "revisionTime": "2015-04-06T19:39:34+02:00"
+ },
+ {
+ "checksumSHA1": "Wahi4g/9XiHhSLAJ+8jskg71PCU=",
+ "path": "github.com/miekg/dns",
+ "revision": "58f52c57ce9df13460ac68200cef30a008b9c468",
+ "revisionTime": "2016-10-18T06:08:08Z"
+ },
+ {
+ "checksumSHA1": "3YJklSuzSE1Rt8A+2dhiWSmf/fw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/pborman/uuid",
+ "path": "github.com/pborman/uuid",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zKKp5SZ3d3ycKe4EKMNT0BqAWBw=",
+ "origin": "github.com/stretchr/testify/vendor/github.com/pmezard/go-difflib/difflib",
+ "path": "github.com/pmezard/go-difflib/difflib",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "KkB+77Ziom7N6RzSbyUwYGrmDeU=",
+ "path": "github.com/prometheus/client_golang/prometheus",
+ "revision": "c5b7fccd204277076155f10851dad72b76a49317",
+ "revisionTime": "2016-08-17T15:48:24Z"
+ },
+ {
+ "checksumSHA1": "DvwvOlPNAgRntBzt3b3OSRMS2N4=",
+ "path": "github.com/prometheus/client_model/go",
+ "revision": "fa8ad6fec33561be4280a8f0514318c79d7f6cb6",
+ "revisionTime": "2015-02-12T10:17:44Z"
+ },
+ {
+ "checksumSHA1": "mHyjbJ3BWOfUV6q9f5PBt0gaY1k=",
+ "path": "github.com/prometheus/common/expfmt",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "GWlM3d2vPYyNATtTFgftS10/A9w=",
+ "path": "github.com/prometheus/common/internal/bitbucket.org/ww/goautoneg",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "UU6hIfhVjnAYDADQEfE/3T7Ddm8=",
+ "path": "github.com/prometheus/common/log",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "nFie+rxcX5WdIv1diZ+fu3aj6lE=",
+ "path": "github.com/prometheus/common/model",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "QQKJYoGcY10nIHxhBEHwjwUZQzk=",
+ "path": "github.com/prometheus/common/route",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "91KYK0SpvkaMJJA2+BcxbVnyRO0=",
+ "path": "github.com/prometheus/common/version",
+ "revision": "85637ea67b04b5c3bb25e671dacded2977f8f9f6",
+ "revisionTime": "2016-10-02T21:02:34Z"
+ },
+ {
+ "checksumSHA1": "W218eJZPXJG783fUr/z6IaAZyes=",
+ "path": "github.com/prometheus/procfs",
+ "revision": "abf152e5f3e97f2fafac028d2cc06c1feb87ffa5",
+ "revisionTime": "2016-04-11T19:08:41Z"
+ },
+ {
+ "checksumSHA1": "+49Vr4Me28p3cR+gxX5SUQHbbas=",
+ "path": "github.com/samuel/go-zookeeper/zk",
+ "revision": "177002e16a0061912f02377e2dd8951a8b3551bc",
+ "revisionTime": "2015-08-17T10:50:50-07:00"
+ },
+ {
+ "checksumSHA1": "YuPBOVkkE3uuBh4RcRUTF0n+frs=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/spf13/pflag",
+ "path": "github.com/spf13/pflag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iydUphwYqZRq3WhstEdGsbvBAKs=",
+ "path": "github.com/stretchr/testify/assert",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "P9FJpir2c4G5PA46qEkaWy3l60U=",
+ "path": "github.com/stretchr/testify/require",
+ "revision": "d77da356e56a7428ad25149ca77381849a6a5232",
+ "revisionTime": "2016-06-15T09:26:46Z"
+ },
+ {
+ "checksumSHA1": "VhcnDY37sYAnL8WjfYQN9YYl+W4=",
+ "path": "github.com/syndtr/goleveldb/leveldb",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "EKIow7XkgNdWvR/982ffIZxKG8Y=",
+ "path": "github.com/syndtr/goleveldb/leveldb/cache",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "5KPgnvCPlR0ysDAqo6jApzRQ3tw=",
+ "path": "github.com/syndtr/goleveldb/leveldb/comparer",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "1DRAxdlWzS4U0xKN/yQ/fdNN7f0=",
+ "path": "github.com/syndtr/goleveldb/leveldb/errors",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "eqKeD6DS7eNCtxVYZEHHRKkyZrw=",
+ "path": "github.com/syndtr/goleveldb/leveldb/filter",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "8dXuAVIsbtaMiGGuHjzGR6Ny/5c=",
+ "path": "github.com/syndtr/goleveldb/leveldb/iterator",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "gJY7bRpELtO0PJpZXgPQ2BYFJ88=",
+ "path": "github.com/syndtr/goleveldb/leveldb/journal",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "j+uaQ6DwJ50dkIdfMQu1TXdlQcY=",
+ "path": "github.com/syndtr/goleveldb/leveldb/memdb",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "UmQeotV+m8/FduKEfLOhjdp18rs=",
+ "path": "github.com/syndtr/goleveldb/leveldb/opt",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "/Wvv9HeJTN9UUjdjwUlz7X4ioIo=",
+ "path": "github.com/syndtr/goleveldb/leveldb/storage",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "JTJA+u8zk7EXy1UUmpFPNGvtO2A=",
+ "path": "github.com/syndtr/goleveldb/leveldb/table",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "4zil8Gwg8VPkDn1YzlgCvtukJFU=",
+ "path": "github.com/syndtr/goleveldb/leveldb/util",
+ "revision": "6b4daa5362b502898ddf367c5c11deb9e7a5c727",
+ "revisionTime": "2016-10-11T05:00:08Z"
+ },
+ {
+ "checksumSHA1": "f6Aew+ZA+HBAXCw6/xTST3mB0Lw=",
+ "origin": "k8s.io/client-go/1.5/vendor/github.com/ugorji/go/codec",
+ "path": "github.com/ugorji/go/codec",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "sFD8LpJPQtWLwGda3edjf5mNUbs=",
+ "path": "github.com/vaughan0/go-ini",
+ "revision": "a98ad7ee00ec53921f08832bc06ecf7fd600e6a1",
+ "revisionTime": "2013-09-23T16:52:12+02:00"
+ },
+ {
+ "checksumSHA1": "9jjO5GjLa0XF/nfWihF02RoH4qc=",
+ "path": "golang.org/x/net/context",
+ "revision": "b336a971b799939dd16ae9b1df8334cb8b977c4d",
+ "revisionTime": "2016-10-27T19:58:04Z"
+ },
+ {
+ "checksumSHA1": "WHc3uByvGaMcnSoI21fhzYgbOgg=",
+ "path": "golang.org/x/net/context/ctxhttp",
+ "revision": "b336a971b799939dd16ae9b1df8334cb8b977c4d",
+ "revisionTime": "2016-10-27T19:58:04Z"
+ },
+ {
+ "checksumSHA1": "SPYGC6DQrH9jICccUsOfbvvhB4g=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/http2",
+ "path": "golang.org/x/net/http2",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EYNaHp7XdLWRydUCE0amEkKAtgk=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/http2/hpack",
+ "path": "golang.org/x/net/http2/hpack",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "gXiSniT8fevWOVPVKopYgrdzi60=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/idna",
+ "path": "golang.org/x/net/idna",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "/k7k6eJDkxXx6K9Zpo/OwNm58XM=",
+ "path": "golang.org/x/net/internal/timeseries",
+ "revision": "6250b412798208e6c90b03b7c4f226de5aa299e2",
+ "revisionTime": "2016-08-24T22:20:41Z"
+ },
+ {
+ "checksumSHA1": "yhndhWXMs/VSEDLks4dNyFMQStA=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/net/lex/httplex",
+ "path": "golang.org/x/net/lex/httplex",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "7WASrg0PEueWDDRHkFhEEN6Qrms=",
+ "path": "golang.org/x/net/netutil",
+ "revision": "bc3663df0ac92f928d419e31e0d2af22e683a5a2",
+ "revisionTime": "2016-06-21T20:48:10Z"
+ },
+ {
+ "checksumSHA1": "mktBVED98G2vv+OKcSgtnFVZC1Y=",
+ "path": "golang.org/x/oauth2",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "2rk6lthfQa5Rfydj8j7+dilKGbo=",
+ "path": "golang.org/x/oauth2/google",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "W/GiDqzsagBnR7/yEvxatMhUDBs=",
+ "path": "golang.org/x/oauth2/internal",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "CPTYHWrVL4jA0B1IuC0hvgcE2AQ=",
+ "path": "golang.org/x/oauth2/jws",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "xifBSq0Pn6pIoPA/o3tyzq8X4Ds=",
+ "path": "golang.org/x/oauth2/jwt",
+ "revision": "65a8d08c6292395d47053be10b3c5e91960def76",
+ "revisionTime": "2016-06-07T03:33:14Z"
+ },
+ {
+ "checksumSHA1": "aVgPDgwY3/t4J/JOw9H3FVMHqh0=",
+ "path": "golang.org/x/sys/unix",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "fpW2dhGFC6SrVzipJx7fjg2DIH8=",
+ "path": "golang.org/x/sys/windows",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "PjYlbMS0ttyZYlaevvjA/gV3g1c=",
+ "path": "golang.org/x/sys/windows/registry",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "uVlUSSKplihZG7N+QJ6fzDZ4Kh8=",
+ "path": "golang.org/x/sys/windows/svc/eventlog",
+ "revision": "c200b10b5d5e122be351b67af224adc6128af5bf",
+ "revisionTime": "2016-10-22T18:22:21Z"
+ },
+ {
+ "checksumSHA1": "QQpKbWuqvhmxVr/hfEYdWzzcXRM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/cases",
+ "path": "golang.org/x/text/cases",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iAsGo/kxvnwILbJVUCd0ZcqZO/Q=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/internal/tag",
+ "path": "golang.org/x/text/internal/tag",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "mQ6PCGHY7K0oPjKbYD8wsTjm/P8=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/language",
+ "path": "golang.org/x/text/language",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "WpeH2TweiuiZAQVTJNO5vyZAQQA=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/runes",
+ "path": "golang.org/x/text/runes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "1VjEPyjdi0xOiIN/Alkqiad/B/c=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/secure/bidirule",
+ "path": "golang.org/x/text/secure/bidirule",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "FcK7VslktIAWj5jnWVnU2SesBq0=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/secure/precis",
+ "path": "golang.org/x/text/secure/precis",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nwlu7UTwYbCj9l5f3a7t2ROwNzM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/transform",
+ "path": "golang.org/x/text/transform",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nWJ9R1+Xw41f/mM3b7BYtv77CfI=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/unicode/bidi",
+ "path": "golang.org/x/text/unicode/bidi",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BAZ96wCGUj6HdY9sG60Yw09KWA4=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/unicode/norm",
+ "path": "golang.org/x/text/unicode/norm",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "AZMILKWqLP99UilLgbGZ+uzIVrM=",
+ "origin": "k8s.io/client-go/1.5/vendor/golang.org/x/text/width",
+ "path": "golang.org/x/text/width",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "AjdmRXf0fiy6Bec9mNlsGsmZi1k=",
+ "path": "google.golang.org/api/compute/v1",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "OtsMVXY89Hc/bBXdDp84atFQawM=",
+ "path": "google.golang.org/api/gensupport",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "yQREK/OWrz9PLljbr127+xFk6J0=",
+ "path": "google.golang.org/api/googleapi",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "ii4ET3JHk3vkMUEcg+9t/1RZSUU=",
+ "path": "google.golang.org/api/googleapi/internal/uritemplates",
+ "revision": "63ade871fd3aec1225809d496e81ec91ab76ea29",
+ "revisionTime": "2016-05-31T06:42:46Z"
+ },
+ {
+ "checksumSHA1": "N3KZEuQ9O1QwJXcCJbe7Czwroo4=",
+ "path": "google.golang.org/appengine",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "G9Xp1ScdsfcKsw+PcWunivRRP3o=",
+ "path": "google.golang.org/appengine/internal",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "x6Thdfyasqd68dWZWqzWWeIfAfI=",
+ "path": "google.golang.org/appengine/internal/app_identity",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "TsNO8P0xUlLNyh3Ic/tzSp/fDWM=",
+ "path": "google.golang.org/appengine/internal/base",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "5QsV5oLGSfKZqTCVXP6NRz5T4Tw=",
+ "path": "google.golang.org/appengine/internal/datastore",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "Gep2T9zmVYV8qZfK2gu3zrmG6QE=",
+ "path": "google.golang.org/appengine/internal/log",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "eLZVX1EHLclFtQnjDIszsdyWRHo=",
+ "path": "google.golang.org/appengine/internal/modules",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "a1XY7rz3BieOVqVI2Et6rKiwQCk=",
+ "path": "google.golang.org/appengine/internal/remote_api",
+ "revision": "4f7eeb5305a4ba1966344836ba4af9996b7b4e05",
+ "revisionTime": "2016-08-19T23:33:10Z"
+ },
+ {
+ "checksumSHA1": "QtAbHtHmDzcf6vOV9eqlCpKgjiw=",
+ "path": "google.golang.org/appengine/internal/urlfetch",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "akOV9pYnCbcPA8wJUutSQVibdyg=",
+ "path": "google.golang.org/appengine/urlfetch",
+ "revision": "267c27e7492265b84fc6719503b14a1e17975d79",
+ "revisionTime": "2016-06-21T05:59:22Z"
+ },
+ {
+ "checksumSHA1": "Wp8g9MHRmK8SwcyGVCoGtPx+5Lo=",
+ "path": "google.golang.org/cloud/compute/metadata",
+ "revision": "0a83eba2cadb60eb22123673c8fb6fca02b03c94",
+ "revisionTime": "2016-06-21T15:59:29Z"
+ },
+ {
+ "checksumSHA1": "U7dGDNwEHORvJFMoNSXErKE7ITg=",
+ "path": "google.golang.org/cloud/internal",
+ "revision": "0a83eba2cadb60eb22123673c8fb6fca02b03c94",
+ "revisionTime": "2016-06-21T15:59:29Z"
+ },
+ {
+ "checksumSHA1": "JfVmsMwyeeepbdw4q4wpN07BuFg=",
+ "path": "gopkg.in/fsnotify.v1",
+ "revision": "30411dbcefb7a1da7e84f75530ad3abe4011b4f8",
+ "revisionTime": "2016-04-12T13:37:56Z"
+ },
+ {
+ "checksumSHA1": "pfQwQtWlFezJq0Viroa/L+v+yDM=",
+ "origin": "k8s.io/client-go/1.5/vendor/gopkg.in/inf.v0",
+ "path": "gopkg.in/inf.v0",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KgT+peLCcuh0/m2mpoOZXuxXmwc=",
+ "path": "gopkg.in/yaml.v2",
+ "revision": "7ad95dd0798a40da1ccdff6dff35fd177b5edf40",
+ "revisionTime": "2015-06-24T11:29:02+01:00"
+ },
+ {
+ "checksumSHA1": "st0Nbu4zwLcP3mz03lDOJVZtn8Y=",
+ "path": "k8s.io/client-go/1.5/discovery",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S+OzpkipMb46LGZoWuveqSLAcoM=",
+ "path": "k8s.io/client-go/1.5/kubernetes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "yCBn8ig1TUMrk+ljtK0nDr7E5Vo=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/apps/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ZRnUz5NrpvJsXAjtnRdEv5UYhSI=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/authentication/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "TY55Np20olmPMzXgfVlIUIyqv04=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/authorization/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "FRByJsFff/6lPH20FtJPaK1NPWI=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/autoscaling/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "3Cy2as7HnQ2FDcvpNbatpFWx0P4=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/batch/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "RUKywApIbSLLsfkYxXzifh7HIvs=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/certificates/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4+Lsxu+sYgzsS2JOHP7CdrZLSKc=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/core/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "H8jzevN03YUfmf2krJt0qj2P9sU=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/extensions/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hrpA6xxtwj3oMcQbFxI2cDhO2ZA=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/policy/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "B2+F12NeMwrOHvHK2ALyEcr3UGA=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/rbac/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "h2eSNUym87RWPlez7UKujShwrUQ=",
+ "path": "k8s.io/client-go/1.5/kubernetes/typed/storage/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "+oIykJ3A0wYjAWbbrGo0jNnMLXw=",
+ "path": "k8s.io/client-go/1.5/pkg/api",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "UsUsIdhuy5Ej2vI0hbmSsrimoaQ=",
+ "path": "k8s.io/client-go/1.5/pkg/api/errors",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Eo6LLHFqG6YznIAKr2mVjuqUj6k=",
+ "path": "k8s.io/client-go/1.5/pkg/api/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "dYznkLcCEai21z1dX8kZY7uDsck=",
+ "path": "k8s.io/client-go/1.5/pkg/api/meta",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "b06esG4xMj/YNFD85Lqq00cx+Yo=",
+ "path": "k8s.io/client-go/1.5/pkg/api/meta/metatypes",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "L9svak1yut0Mx8r9VLDOwpqZzBk=",
+ "path": "k8s.io/client-go/1.5/pkg/api/resource",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "m7jGshKDLH9kdokfa6MwAqzxRQk=",
+ "path": "k8s.io/client-go/1.5/pkg/api/unversioned",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "iI6s5WAexr1PEfqrbvuscB+oVik=",
+ "path": "k8s.io/client-go/1.5/pkg/api/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ikac34qI/IkTWHnfi8pPl9irPyo=",
+ "path": "k8s.io/client-go/1.5/pkg/api/validation/path",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "MJyygSPp8N6z+7SPtcROz4PEwas=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EGb4IcSTQ1VXCmX0xcyG5GpWId8=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery/announced",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "vhSyuINHQhCsDKTyBmvJT1HzDHI=",
+ "path": "k8s.io/client-go/1.5/pkg/apimachinery/registered",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rXeBnwLg8ZFe6m5/Ki7tELVBYDk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KzHaG858KV1tBh5cuLInNcm+G5s=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "fynWdchlRbPaxuST2oGDKiKLTqE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/apps/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "hreIYssoH4Ef/+Aglpitn3GNLR4=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EgUqJH4CqB9vXVg6T8II2OEt5LE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Z3DKgomzRPGcBv/8hlL6pfnIpXI=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authentication/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "GpuScB2Z+NOT4WIQg1mVvVSDUts=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "+u3UD+HY9lBH+PFi/2B4W564JEw=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "zIFzgWjmlWNLHGHMpCpDCvoLtKY=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/authorization/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "tdpzQFQyVkt5kCLTvtKTVqT+maE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nb6LbYGS5tv8H8Ovptg6M7XuDZ4=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "DNb1/nl/5RDdckRrJoXBRagzJXs=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/autoscaling/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "4bLhH2vNl5l4Qp6MjLhWyWVAPE0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "RpAAEynmxlvOlLLZK1KEUQRnYzk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "uWJ2BHmjL/Gq4FFlNkqiN6vvPyM=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/v1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "mHWt/p724dKeP1vqLtWQCye7zaE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/batch/v2alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "6dJ1dGfXkB3A42TOtMaY/rvv4N8=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Bkrhm6HbFYANwtzUE8eza9SWBk0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nRRPIBQ5O3Ad24kscNtK+gPC+fk=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/certificates/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KUMhoaOg9GXHN/aAVvSLO18SgqU=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "eSo2VhNAYtesvmpEPqn05goW4LY=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "DunWIPrCC5iGMWzkaaugMOxD+hg=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/extensions/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rVGYi2ko0E7vL5OZSMYX+NAGPYw=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "llJHd2H0LzABGB6BcletzIHnexo=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "j44bqyY13ldnuCtysYE8nRkMD7o=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/policy/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "vT7rFxowcKMTYc55mddePqUFRgE=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "r1MzUXsG+Zyn30aU8I5R5dgrJPA=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "aNfO8xn8VDO3fM9CpVCe6EIB+GA=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/rbac/v1alpha1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "rQCxrbisCXmj2wymlYG63kcTL9I=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wZyxh5nt5Eh6kF7YNAIYukKWWy0=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage/install",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P8ANOt/I4Cs3QtjVXWmDA/gpQdg=",
+ "path": "k8s.io/client-go/1.5/pkg/apis/storage/v1beta1",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "qnVPwzvNLz2mmr3BXdU9qIhQXXU=",
+ "path": "k8s.io/client-go/1.5/pkg/auth/user",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KrIchxhapSs242yAy8yrTS1XlZo=",
+ "path": "k8s.io/client-go/1.5/pkg/conversion",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "weZqKFcOhcnF47eDDHXzluCKSF0=",
+ "path": "k8s.io/client-go/1.5/pkg/conversion/queryparams",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "T3EMfyXZX5939/OOQ1JU+Nmbk4k=",
+ "path": "k8s.io/client-go/1.5/pkg/fields",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "2v11s3EBH8UBl2qfImT29tQN2kM=",
+ "path": "k8s.io/client-go/1.5/pkg/genericapiserver/openapi/common",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "GvBlph6PywK3zguou/T9kKNNdoQ=",
+ "path": "k8s.io/client-go/1.5/pkg/labels",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Vtrgy827r0rWzIAgvIWY4flu740=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "SEcZqRATexhgHvDn+eHvMc07UJs=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "qzYKG9YZSj8l/W1QVTOrGAry/BM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/json",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "F7h+8zZ0JPLYkac4KgSVljguBE4=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/protobuf",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "CvySOL8C85e3y7EWQ+Au4cwUZJM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/recognizer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "eCitoKeIun+lJzYFhAfdSIIicSM=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/streaming",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "kVWvZuLGltJ4YqQsiaCLRRLDDK0=",
+ "path": "k8s.io/client-go/1.5/pkg/runtime/serializer/versioning",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "m51+LAeQ9RK1KHX+l2iGcwbVCKs=",
+ "path": "k8s.io/client-go/1.5/pkg/selection",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "dp4IWcC3U6a0HeOdVCDQWODWCbw=",
+ "path": "k8s.io/client-go/1.5/pkg/third_party/forked/golang/reflect",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ER898XJD1ox4d71gKZD8TLtTSpM=",
+ "path": "k8s.io/client-go/1.5/pkg/types",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "BVdXtnLDlmBQksRPfHOIG+qdeVg=",
+ "path": "k8s.io/client-go/1.5/pkg/util",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "nnh8Sa4dCupxRI4bbKaozGp1d/A=",
+ "path": "k8s.io/client-go/1.5/pkg/util/cert",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S32d5uduNlwouM8+mIz+ALpliUQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/clock",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Y6rWC0TUw2/uUeUjJ7kazyEUzBQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/errors",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "C7IfEAdCOePw3/IraaZCNXuYXLw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/flowcontrol",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "EuslQHnhBSRXaWimYqLEqhMPV48=",
+ "path": "k8s.io/client-go/1.5/pkg/util/framer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ByO18NbZwiifFr8qtLyfJAHXguA=",
+ "path": "k8s.io/client-go/1.5/pkg/util/integer",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ww+RfsoIlUBDwThg2oqC5QVz33Y=",
+ "path": "k8s.io/client-go/1.5/pkg/util/intstr",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "7E8f8dLlXW7u6r9sggMjvB4HEiw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/json",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "d0pFZxMJG9j95acNmaIM1l+X+QU=",
+ "path": "k8s.io/client-go/1.5/pkg/util/labels",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wCN7u1lE+25neM9jXeI7aE8EAfk=",
+ "path": "k8s.io/client-go/1.5/pkg/util/net",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "g+kBkxcb+tYmFtRRly+VE+JAIfw=",
+ "path": "k8s.io/client-go/1.5/pkg/util/parsers",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "S4wUnE5VkaWWrkLbgPL/1oNLJ4g=",
+ "path": "k8s.io/client-go/1.5/pkg/util/rand",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "8j9c2PqTKybtnymXbStNYRexRj8=",
+ "path": "k8s.io/client-go/1.5/pkg/util/runtime",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "aAz4e8hLGs0+ZAz1TdA5tY/9e1A=",
+ "path": "k8s.io/client-go/1.5/pkg/util/sets",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P/fwh6QZ5tsjVyHTaASDWL3WaGs=",
+ "path": "k8s.io/client-go/1.5/pkg/util/uuid",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "P9Bq/1qbF4SvnN9HyCTRpbUz7sQ=",
+ "path": "k8s.io/client-go/1.5/pkg/util/validation",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "D0JIEjlP69cuPOZEdsSKeFgsnI8=",
+ "path": "k8s.io/client-go/1.5/pkg/util/validation/field",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "T7ba8t8i+BtgClMgL+aMZM94fcI=",
+ "path": "k8s.io/client-go/1.5/pkg/util/wait",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "6RCTv/KDiw7as4KeyrgU3XrUSQI=",
+ "path": "k8s.io/client-go/1.5/pkg/util/yaml",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "OwKlsSeKtz1FBVC9cQ5gWRL5pKc=",
+ "path": "k8s.io/client-go/1.5/pkg/version",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Oil9WGw/dODbpBopn6LWQGS3DYg=",
+ "path": "k8s.io/client-go/1.5/pkg/watch",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "r5alnRCbLaPsbTeJjjTVn/bt6uw=",
+ "path": "k8s.io/client-go/1.5/pkg/watch/versioned",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "X1+ltyfHui/XCwDupXIf39+9gWQ=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "KYy+js37AS0ZT08g5uBr1ZoMPmE=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth/gcp",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "wQ9G5++lbQpejqCzGHo037N3YcY=",
+ "path": "k8s.io/client-go/1.5/plugin/pkg/client/auth/oidc",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "ABe8YfZVEDoRpAUqp2BKP8o1VIA=",
+ "path": "k8s.io/client-go/1.5/rest",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "Gbe0Vs9hkI7X5hhbXUuWdRFffSI=",
+ "path": "k8s.io/client-go/1.5/tools/cache",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "K/oOznXABjqSS1c2Fs407c5F8KA=",
+ "path": "k8s.io/client-go/1.5/tools/clientcmd/api",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "c1PQ4WJRfpA9BYcFHW2+46hu5IE=",
+ "path": "k8s.io/client-go/1.5/tools/metrics",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ },
+ {
+ "checksumSHA1": "e4W2q+6wvjejv3V0UCI1mewTTro=",
+ "path": "k8s.io/client-go/1.5/transport",
+ "revision": "c589d0c9f0d81640c518354c7bcae77d99820aa3",
+ "revisionTime": "2016-09-30T00:14:02Z"
+ }
+ ],
+ "rootPath": "github.com/prometheus/prometheus"
+}
diff --git a/src/cmd/go/internal/modconv/testdata/upspin.dep b/src/cmd/go/internal/modconv/testdata/upspin.dep
new file mode 100644
index 0000000000..be77bcb928
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/upspin.dep
@@ -0,0 +1,57 @@
+# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'.
+
+
+[[projects]]
+ branch = "master"
+ name = "bazil.org/fuse"
+ packages = [".","fs","fuseutil"]
+ revision = "371fbbdaa8987b715bdd21d6adc4c9b20155f748"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/NYTimes/gziphandler"
+ packages = ["."]
+ revision = "97ae7fbaf81620fe97840685304a78a306a39c64"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/golang/protobuf"
+ packages = ["proto"]
+ revision = "1643683e1b54a9e88ad26d98f81400c8c9d9f4f9"
+
+[[projects]]
+ branch = "master"
+ name = "github.com/russross/blackfriday"
+ packages = ["."]
+ revision = "6d1ef893fcb01b4f50cb6e57ed7df3e2e627b6b2"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/crypto"
+ packages = ["acme","acme/autocert","hkdf"]
+ revision = "13931e22f9e72ea58bb73048bc752b48c6d4d4ac"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/net"
+ packages = ["context"]
+ revision = "4b14673ba32bee7f5ac0f990a48f033919fd418b"
+
+[[projects]]
+ branch = "master"
+ name = "golang.org/x/text"
+ packages = ["cases","internal","internal/gen","internal/tag","internal/triegen","internal/ucd","language","runes","secure/bidirule","secure/precis","transform","unicode/bidi","unicode/cldr","unicode/norm","unicode/rangetable","width"]
+ revision = "6eab0e8f74e86c598ec3b6fad4888e0c11482d48"
+
+[[projects]]
+ branch = "v2"
+ name = "gopkg.in/yaml.v2"
+ packages = ["."]
+ revision = "eb3733d160e74a9c7e442f435eb3bea458e1d19f"
+
+[solve-meta]
+ analyzer-name = "dep"
+ analyzer-version = 1
+ inputs-digest = "2246e647ba1c78b0b9f948f9fb072fff1467284fb138709c063e99736f646b90"
+ solver-name = "gps-cdcl"
+ solver-version = 1
diff --git a/src/cmd/go/internal/modconv/testdata/upspin.out b/src/cmd/go/internal/modconv/testdata/upspin.out
new file mode 100644
index 0000000000..00597db848
--- /dev/null
+++ b/src/cmd/go/internal/modconv/testdata/upspin.out
@@ -0,0 +1,8 @@
+bazil.org/fuse 371fbbdaa8987b715bdd21d6adc4c9b20155f748
+github.com/NYTimes/gziphandler 97ae7fbaf81620fe97840685304a78a306a39c64
+github.com/golang/protobuf 1643683e1b54a9e88ad26d98f81400c8c9d9f4f9
+github.com/russross/blackfriday 6d1ef893fcb01b4f50cb6e57ed7df3e2e627b6b2
+golang.org/x/crypto 13931e22f9e72ea58bb73048bc752b48c6d4d4ac
+golang.org/x/net 4b14673ba32bee7f5ac0f990a48f033919fd418b
+golang.org/x/text 6eab0e8f74e86c598ec3b6fad4888e0c11482d48
+gopkg.in/yaml.v2 eb3733d160e74a9c7e442f435eb3bea458e1d19f
diff --git a/src/cmd/go/internal/modconv/tsv.go b/src/cmd/go/internal/modconv/tsv.go
new file mode 100644
index 0000000000..fd3364934f
--- /dev/null
+++ b/src/cmd/go/internal/modconv/tsv.go
@@ -0,0 +1,23 @@
+// Copyright 2018 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 modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/module"
+)
+
+func ParseDependenciesTSV(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ f := strings.Split(line, "\t")
+ if len(f) >= 3 {
+ list = append(list, module.Version{Path: f[0], Version: f[2]})
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/vconf.go b/src/cmd/go/internal/modconv/vconf.go
new file mode 100644
index 0000000000..5d3cd3c917
--- /dev/null
+++ b/src/cmd/go/internal/modconv/vconf.go
@@ -0,0 +1,26 @@
+// Copyright 2018 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 modconv
+
+import (
+ "strings"
+
+ "cmd/go/internal/module"
+)
+
+func ParseVendorConf(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if i := strings.Index(line, "#"); i >= 0 {
+ line = line[:i]
+ }
+ f := strings.Fields(line)
+ if len(f) >= 2 {
+ list = append(list, module.Version{Path: f[0], Version: f[1]})
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/vjson.go b/src/cmd/go/internal/modconv/vjson.go
new file mode 100644
index 0000000000..38b0a685ad
--- /dev/null
+++ b/src/cmd/go/internal/modconv/vjson.go
@@ -0,0 +1,28 @@
+// Copyright 2018 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 modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/module"
+)
+
+func ParseVendorJSON(file string, data []byte) ([]module.Version, error) {
+ var cfg struct {
+ Package []struct {
+ Path string
+ Revision string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ var list []module.Version
+ for _, d := range cfg.Package {
+ list = append(list, module.Version{Path: d.Path, Version: d.Revision})
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/vmanifest.go b/src/cmd/go/internal/modconv/vmanifest.go
new file mode 100644
index 0000000000..f2cf0f58f2
--- /dev/null
+++ b/src/cmd/go/internal/modconv/vmanifest.go
@@ -0,0 +1,28 @@
+// Copyright 2018 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 modconv
+
+import (
+ "encoding/json"
+
+ "cmd/go/internal/module"
+)
+
+func ParseVendorManifest(file string, data []byte) ([]module.Version, error) {
+ var cfg struct {
+ Dependencies []struct {
+ ImportPath string
+ Revision string
+ }
+ }
+ if err := json.Unmarshal(data, &cfg); err != nil {
+ return nil, err
+ }
+ var list []module.Version
+ for _, d := range cfg.Dependencies {
+ list = append(list, module.Version{Path: d.ImportPath, Version: d.Revision})
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modconv/vyml.go b/src/cmd/go/internal/modconv/vyml.go
new file mode 100644
index 0000000000..e2ea9e3e9c
--- /dev/null
+++ b/src/cmd/go/internal/modconv/vyml.go
@@ -0,0 +1,40 @@
+// Copyright 2018 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 modconv
+
+import (
+ "cmd/go/internal/module"
+ "strings"
+)
+
+func ParseVendorYML(file string, data []byte) ([]module.Version, error) {
+ var list []module.Version
+ vendors := false
+ path := ""
+ for lineno, line := range strings.Split(string(data), "\n") {
+ lineno++
+ if line == "" {
+ continue
+ }
+ if strings.HasPrefix(line, "vendors:") {
+ vendors = true
+ } else if line[0] != '-' && line[0] != ' ' && line[0] != '\t' {
+ vendors = false
+ }
+ if !vendors {
+ continue
+ }
+ if strings.HasPrefix(line, "- path:") {
+ path = strings.TrimSpace(line[len("- path:"):])
+ }
+ if strings.HasPrefix(line, " rev:") {
+ rev := strings.TrimSpace(line[len(" rev:"):])
+ if path != "" && rev != "" {
+ list = append(list, module.Version{Path: path, Version: rev})
+ }
+ }
+ }
+ return list, nil
+}
diff --git a/src/cmd/go/internal/modfetch/bitbucket/fetch.go b/src/cmd/go/internal/modfetch/bitbucket/fetch.go
new file mode 100644
index 0000000000..c077a3eb74
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/bitbucket/fetch.go
@@ -0,0 +1,22 @@
+// Copyright 2018 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 bitbucket
+
+import (
+ "fmt"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/gitrepo"
+)
+
+func Lookup(path string) (codehost.Repo, error) {
+ f := strings.Split(path, "/")
+ if len(f) < 3 || f[0] != "bitbucket.org" {
+ return nil, fmt.Errorf("bitbucket repo must be bitbucket.org/org/project")
+ }
+ path = f[0] + "/" + f[1] + "/" + f[2]
+ return gitrepo.Repo("https://"+path, path)
+}
diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go
new file mode 100644
index 0000000000..0e3bb7d7c3
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/codehost/codehost.go
@@ -0,0 +1,187 @@
+// Copyright 2018 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 codehost defines the interface implemented by a code hosting source,
+// along with support code for use by implementations.
+package codehost
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "strings"
+ "time"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/str"
+)
+
+// Downloaded size limits.
+const (
+ MaxGoMod = 16 << 20 // maximum size of go.mod file
+ MaxLICENSE = 16 << 20 // maximum size of LICENSE file
+ MaxZipFile = 500 << 20 // maximum size of downloaded zip file
+)
+
+// A Repo represents a code hosting source.
+// Typical implementations include local version control repositories,
+// remote version control servers, and code hosting sites.
+type Repo interface {
+ // Root returns the import path of the root directory of the repository.
+ Root() string
+
+ // List lists all tags with the given prefix.
+ Tags(prefix string) (tags []string, err error)
+
+ // Stat returns information about the revision rev.
+ // A revision can be any identifier known to the underlying service:
+ // commit hash, branch, tag, and so on.
+ Stat(rev string) (*RevInfo, error)
+
+ // Latest returns the latest revision on the default branch,
+ // whatever that means in the underlying implementation.
+ Latest() (*RevInfo, error)
+
+ // ReadFile reads the given file in the file tree corresponding to revision rev.
+ // It should refuse to read more than maxSize bytes.
+ ReadFile(rev, file string, maxSize int64) (data []byte, err error)
+
+ // ReadZip downloads a zip file for the subdir subdirectory
+ // of the given revision to a new file in a given temporary directory.
+ // It should refuse to read more than maxSize bytes.
+ // It returns a ReadCloser for a streamed copy of the zip file,
+ // along with the actual subdirectory (possibly shorter than subdir)
+ // contained in the zip file. All files in the zip file are expected to be
+ // nested in a single top-level directory, whose name is not specified.
+ ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error)
+}
+
+// A Rev describes a single revision in a source code repository.
+type RevInfo struct {
+ Name string // complete ID in underlying repository
+ Short string // shortened ID, for use in pseudo-version
+ Version string // TODO what is this?
+ Time time.Time // commit time
+}
+
+// AllHex reports whether the revision rev is entirely lower-case hexadecimal digits.
+func AllHex(rev string) bool {
+ for i := 0; i < len(rev); i++ {
+ c := rev[i]
+ if '0' <= c && c <= '9' || 'a' <= c && c <= 'f' {
+ continue
+ }
+ return false
+ }
+ return true
+}
+
+// ShortenSHA1 shortens a SHA1 hash (40 hex digits) to the canonical length
+// used in pseudo-versions (12 hex digits).
+func ShortenSHA1(rev string) string {
+ if AllHex(rev) && len(rev) == 40 {
+ return rev[:12]
+ }
+ return rev
+}
+
+// WorkRoot is the root of the cached work directory.
+// It is set by cmd/go/internal/vgo.InitMod.
+var WorkRoot string
+
+// WorkDir returns the name of the cached work directory to use for the
+// given repository type and name.
+func WorkDir(typ, name string) (string, error) {
+ if WorkRoot == "" {
+ return "", fmt.Errorf("codehost.WorkRoot not set")
+ }
+
+ // We name the work directory for the SHA256 hash of the type and name.
+ // We intentionally avoid the actual name both because of possible
+ // conflicts with valid file system paths and because we want to ensure
+ // that one checkout is never nested inside another. That nesting has
+ // led to security problems in the past.
+ if strings.Contains(typ, ":") {
+ return "", fmt.Errorf("codehost.WorkDir: type cannot contain colon")
+ }
+ key := typ + ":" + name
+ dir := filepath.Join(WorkRoot, fmt.Sprintf("%x", sha256.Sum256([]byte(key))))
+ data, err := ioutil.ReadFile(dir + ".info")
+ if err == nil {
+ have := strings.TrimSuffix(string(data), "\n")
+ if have != key {
+ return "", fmt.Errorf("%s exists with wrong content (have %q want %q)", dir+".info", have, key)
+ }
+ _, err := os.Stat(dir)
+ if err != nil {
+ return "", fmt.Errorf("%s exists but %s does not", dir+".info", dir)
+ }
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "# %s for %s %s\n", dir, typ, name)
+ }
+ return dir, nil
+ }
+
+ if cfg.BuildX {
+ fmt.Fprintf(os.Stderr, "mkdir -p %s # %s %s\n", dir, typ, name)
+ }
+ os.RemoveAll(dir)
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return "", err
+ }
+ if err := ioutil.WriteFile(dir+".info", []byte(key), 0666); err != nil {
+ os.RemoveAll(dir)
+ return "", err
+ }
+ return dir, nil
+}
+
+type RunError struct {
+ Cmd string
+ Err error
+ Stderr []byte
+}
+
+func (e *RunError) Error() string {
+ text := e.Cmd + ": " + e.Err.Error()
+ stderr := bytes.TrimRight(e.Stderr, "\n")
+ if len(stderr) > 0 {
+ text += ":\n\t" + strings.Replace(string(stderr), "\n", "\n\t", -1)
+ }
+ return text
+}
+
+// Run runs the command line in the given directory
+// (an empty dir means the current directory).
+// It returns the standard output and, for a non-zero exit,
+// a *RunError indicating the command, exit status, and standard error.
+// Standard error is unavailable for commands that exit successfully.
+func Run(dir string, cmdline ...interface{}) ([]byte, error) {
+ cmd := str.StringList(cmdline...)
+ if cfg.BuildX {
+ var cd string
+ if dir != "" {
+ cd = "cd " + dir + "; "
+ }
+ fmt.Fprintf(os.Stderr, "%s%s\n", cd, strings.Join(cmd, " "))
+ }
+ // TODO: Impose limits on command output size.
+ // TODO: Set environment to get English error messages.
+ var stderr bytes.Buffer
+ var stdout bytes.Buffer
+ c := exec.Command(cmd[0], cmd[1:]...)
+ c.Dir = dir
+ c.Stderr = &stderr
+ c.Stdout = &stdout
+ err := c.Run()
+ if err != nil {
+ err = &RunError{Cmd: strings.Join(cmd, " ") + " in " + dir, Stderr: stderr.Bytes(), Err: err}
+ }
+ return stdout.Bytes(), err
+}
diff --git a/src/cmd/go/internal/modfetch/coderepo.go b/src/cmd/go/internal/modfetch/coderepo.go
new file mode 100644
index 0000000000..bb6e8ac179
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/coderepo.go
@@ -0,0 +1,576 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "archive/zip"
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+ "time"
+
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+// A codeRepo implements modfetch.Repo using an underlying codehost.Repo.
+type codeRepo struct {
+ modPath string
+ code codehost.Repo
+ codeRoot string
+ codeDir string
+
+ path string
+ pathPrefix string
+ pathMajor string
+ pseudoMajor string
+}
+
+func newCodeRepo(code codehost.Repo, path string) (Repo, error) {
+ codeRoot := code.Root()
+ if !hasPathPrefix(path, codeRoot) {
+ return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path)
+ }
+ pathPrefix, pathMajor, ok := module.SplitPathVersion(path)
+ if !ok {
+ return nil, fmt.Errorf("invalid module path %q", path)
+ }
+ pseudoMajor := "v0"
+ if pathMajor != "" {
+ pseudoMajor = pathMajor[1:]
+ }
+
+ // At this point we might have:
+ // codeRoot = github.com/rsc/foo
+ // path = github.com/rsc/foo/bar/v2
+ // pathPrefix = github.com/rsc/foo/bar
+ // pathMajor = /v2
+ // pseudoMajor = v2
+ //
+ // Compute codeDir = bar, the subdirectory within the repo
+ // corresponding to the module root.
+ codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, codeRoot), "/")
+ if strings.HasPrefix(path, "gopkg.in/") {
+ // But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot.
+ // For example we might have:
+ // codeRoot = gopkg.in/yaml.v2
+ // pathPrefix = gopkg.in/yaml
+ // pathMajor = .v2
+ // pseudoMajor = v2
+ // codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix)
+ // Clear codeDir - the module root is the repo root for gopkg.in repos.
+ codeDir = ""
+ }
+
+ r := &codeRepo{
+ modPath: path,
+ code: code,
+ codeRoot: codeRoot,
+ codeDir: codeDir,
+ pathPrefix: pathPrefix,
+ pathMajor: pathMajor,
+ pseudoMajor: pseudoMajor,
+ }
+
+ return r, nil
+}
+
+func (r *codeRepo) ModulePath() string {
+ return r.modPath
+}
+
+func (r *codeRepo) Versions(prefix string) ([]string, error) {
+ p := prefix
+ if r.codeDir != "" {
+ p = r.codeDir + "/" + p
+ }
+ tags, err := r.code.Tags(p)
+ if err != nil {
+ return nil, err
+ }
+ list := []string{}
+ for _, tag := range tags {
+ if !strings.HasPrefix(tag, p) {
+ continue
+ }
+ v := tag
+ if r.codeDir != "" {
+ v = v[len(r.codeDir)+1:]
+ }
+ if !semver.IsValid(v) || v != semver.Canonical(v) || isPseudoVersion(v) || !module.MatchPathMajor(v, r.pathMajor) {
+ continue
+ }
+ list = append(list, v)
+ }
+ SortVersions(list)
+ return list, nil
+}
+
+func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
+ if rev == "latest" {
+ return r.Latest()
+ }
+ codeRev := r.revToRev(rev)
+ if semver.IsValid(codeRev) && r.codeDir != "" {
+ codeRev = r.codeDir + "/" + codeRev
+ }
+ info, err := r.code.Stat(codeRev)
+ if err != nil {
+ return nil, err
+ }
+ return r.convert(info)
+}
+
+func (r *codeRepo) Latest() (*RevInfo, error) {
+ info, err := r.code.Latest()
+ if err != nil {
+ return nil, err
+ }
+ return r.convert(info)
+}
+
+func (r *codeRepo) convert(info *codehost.RevInfo) (*RevInfo, error) {
+ versionOK := func(v string) bool {
+ return semver.IsValid(v) && v == semver.Canonical(v) && !isPseudoVersion(v) && module.MatchPathMajor(v, r.pathMajor)
+ }
+ v := info.Version
+ if r.codeDir == "" {
+ if !versionOK(v) {
+ v = PseudoVersion(r.pseudoMajor, info.Time, info.Short)
+ }
+ } else {
+ p := r.codeDir + "/"
+ if strings.HasPrefix(v, p) && versionOK(v[len(p):]) {
+ v = v[len(p):]
+ } else {
+ v = PseudoVersion(r.pseudoMajor, info.Time, info.Short)
+ }
+ }
+
+ info2 := &RevInfo{
+ Name: info.Name,
+ Short: info.Short,
+ Time: info.Time,
+ Version: v,
+ }
+ return info2, nil
+}
+
+func (r *codeRepo) revToRev(rev string) string {
+ if semver.IsValid(rev) {
+ if isPseudoVersion(rev) {
+ i := strings.Index(rev, "-")
+ j := strings.Index(rev[i+1:], "-")
+ return rev[i+1+j+1:]
+ }
+ if r.codeDir == "" {
+ return rev
+ }
+ return r.codeDir + "/" + rev
+ }
+ return rev
+}
+
+func (r *codeRepo) versionToRev(version string) (rev string, err error) {
+ if !semver.IsValid(version) {
+ return "", fmt.Errorf("malformed semantic version %q", version)
+ }
+ return r.revToRev(version), nil
+}
+
+func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err error) {
+ rev, err = r.versionToRev(version)
+ if err != nil {
+ return "", "", nil, err
+ }
+ if r.pathMajor == "" || strings.HasPrefix(r.pathMajor, ".") {
+ if r.codeDir == "" {
+ return rev, "", nil, nil
+ }
+ file1 := path.Join(r.codeDir, "go.mod")
+ gomod1, err1 := r.code.ReadFile(rev, file1, codehost.MaxGoMod)
+ if err1 != nil {
+ return "", "", nil, fmt.Errorf("missing go.mod")
+ }
+ return rev, r.codeDir, gomod1, nil
+ }
+
+ // Suppose pathMajor is "/v2".
+ // Either go.mod should claim v2 and v2/go.mod should not exist,
+ // or v2/go.mod should exist and claim v2. Not both.
+ // Note that we don't check the full path, just the major suffix,
+ // because of replacement modules. This might be a fork of
+ // the real module, found at a different path, usable only in
+ // a replace directive.
+ file1 := path.Join(r.codeDir, "go.mod")
+ file2 := path.Join(r.codeDir, r.pathMajor[1:], "go.mod")
+ gomod1, err1 := r.code.ReadFile(rev, file1, codehost.MaxGoMod)
+ gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod)
+ found1 := err1 == nil && isMajor(gomod1, r.pathMajor)
+ found2 := err2 == nil && isMajor(gomod2, r.pathMajor)
+
+ if err2 == nil && !found2 {
+ return "", "", nil, fmt.Errorf("%s has non-...%s module path", file2, r.pathMajor)
+ }
+ if found1 && found2 {
+ return "", "", nil, fmt.Errorf("both %s and %s claim ...%s module", file1, file2, r.pathMajor)
+ }
+ if found2 {
+ return rev, filepath.Join(r.codeDir, r.pathMajor), gomod2, nil
+ }
+ if found1 {
+ return rev, r.codeDir, gomod1, nil
+ }
+ return "", "", nil, fmt.Errorf("missing or invalid go.mod")
+}
+
+func isMajor(gomod []byte, pathMajor string) bool {
+ return strings.HasSuffix(modPath(gomod), pathMajor)
+}
+
+var moduleStr = []byte("module")
+
+func modPath(mod []byte) string {
+ for len(mod) > 0 {
+ line := mod
+ mod = nil
+ if i := bytes.IndexByte(line, '\n'); i >= 0 {
+ line, mod = line[:i], line[i+1:]
+ }
+ line = bytes.TrimSpace(line)
+ if !bytes.HasPrefix(line, moduleStr) {
+ continue
+ }
+ line = line[len(moduleStr):]
+ n := len(line)
+ line = bytes.TrimSpace(line)
+ if len(line) == n || len(line) == 0 {
+ continue
+ }
+
+ if line[0] == '"' || line[0] == '`' {
+ p, err := strconv.Unquote(string(line))
+ if err != nil {
+ return "" // malformed quoted string or multiline module path
+ }
+ return p
+ }
+
+ return string(line)
+ }
+ return "" // missing module path
+}
+
+func (r *codeRepo) GoMod(version string) (data []byte, err error) {
+ rev, dir, gomod, err := r.findDir(version)
+ if err != nil {
+ return nil, err
+ }
+ if gomod != nil {
+ return gomod, nil
+ }
+ data, err = r.code.ReadFile(rev, path.Join(dir, "go.mod"), codehost.MaxGoMod)
+ if err != nil {
+ if e := strings.ToLower(err.Error()); strings.Contains(e, "not found") || strings.Contains(e, "404") { // TODO
+ return r.legacyGoMod(rev, dir), nil
+ }
+ return nil, err
+ }
+ return data, nil
+}
+
+var altConfigs = []string{
+ "Gopkg.lock",
+
+ "GLOCKFILE",
+ "Godeps/Godeps.json",
+ "dependencies.tsv",
+ "glide.lock",
+ "vendor.conf",
+ "vendor.yml",
+ "vendor/manifest",
+ "vendor/vendor.json",
+}
+
+func (r *codeRepo) legacyGoMod(rev, dir string) []byte {
+ mf := new(modfile.File)
+ mf.AddModuleStmt(r.modPath)
+ for _, file := range altConfigs {
+ data, err := r.code.ReadFile(rev, path.Join(dir, file), codehost.MaxGoMod)
+ if err != nil {
+ continue
+ }
+ convert := modconv.Converters[file]
+ if convert == nil {
+ continue
+ }
+ if err := ConvertLegacyConfig(mf, file, data); err != nil {
+ continue
+ }
+ break
+ }
+ data, err := mf.Format()
+ if err != nil {
+ return []byte(fmt.Sprintf("%s\nmodule %q\n", modconv.Prefix, r.modPath))
+ }
+ return append([]byte(modconv.Prefix+"\n"), data...)
+}
+
+func (r *codeRepo) modPrefix(rev string) string {
+ return r.modPath + "@" + rev
+}
+
+func (r *codeRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+ rev, dir, _, err := r.findDir(version)
+ if err != nil {
+ return "", err
+ }
+ dl, actualDir, err := r.code.ReadZip(rev, dir, codehost.MaxZipFile)
+ if err != nil {
+ return "", err
+ }
+ if actualDir != "" && !hasPathPrefix(dir, actualDir) {
+ return "", fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
+ }
+ subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/")
+
+ // Spool to local file.
+ f, err := ioutil.TempFile(tmpdir, "vgo-codehost-")
+ if err != nil {
+ dl.Close()
+ return "", err
+ }
+ defer os.Remove(f.Name())
+ defer f.Close()
+ maxSize := int64(codehost.MaxZipFile)
+ lr := &io.LimitedReader{R: dl, N: maxSize + 1}
+ if _, err := io.Copy(f, lr); err != nil {
+ dl.Close()
+ return "", err
+ }
+ dl.Close()
+ if lr.N <= 0 {
+ return "", fmt.Errorf("downloaded zip file too large")
+ }
+ size := (maxSize + 1) - lr.N
+ if _, err := f.Seek(0, 0); err != nil {
+ return "", err
+ }
+
+ // Translate from zip file we have to zip file we want.
+ zr, err := zip.NewReader(f, size)
+ if err != nil {
+ return "", err
+ }
+ f2, err := ioutil.TempFile(tmpdir, "vgo-")
+ if err != nil {
+ return "", err
+ }
+
+ zw := zip.NewWriter(f2)
+ newName := f2.Name()
+ defer func() {
+ f2.Close()
+ if err != nil {
+ os.Remove(newName)
+ }
+ }()
+ if subdir != "" {
+ subdir += "/"
+ }
+ haveLICENSE := false
+ topPrefix := ""
+ haveGoMod := make(map[string]bool)
+ for _, zf := range zr.File {
+ if topPrefix == "" {
+ i := strings.Index(zf.Name, "/")
+ if i < 0 {
+ return "", fmt.Errorf("missing top-level directory prefix")
+ }
+ topPrefix = zf.Name[:i+1]
+ }
+ if !strings.HasPrefix(zf.Name, topPrefix) {
+ return "", fmt.Errorf("zip file contains more than one top-level directory")
+ }
+ dir, file := path.Split(zf.Name)
+ if file == "go.mod" {
+ haveGoMod[dir] = true
+ }
+ }
+ root := topPrefix + subdir
+ inSubmodule := func(name string) bool {
+ for {
+ dir, _ := path.Split(name)
+ if len(dir) <= len(root) {
+ return false
+ }
+ if haveGoMod[dir] {
+ return true
+ }
+ name = dir[:len(dir)-1]
+ }
+ }
+ for _, zf := range zr.File {
+ if topPrefix == "" {
+ i := strings.Index(zf.Name, "/")
+ if i < 0 {
+ return "", fmt.Errorf("missing top-level directory prefix")
+ }
+ topPrefix = zf.Name[:i+1]
+ }
+ if strings.HasSuffix(zf.Name, "/") { // drop directory dummy entries
+ continue
+ }
+ if !strings.HasPrefix(zf.Name, topPrefix) {
+ return "", fmt.Errorf("zip file contains more than one top-level directory")
+ }
+ name := strings.TrimPrefix(zf.Name, topPrefix)
+ if !strings.HasPrefix(name, subdir) {
+ continue
+ }
+ name = strings.TrimPrefix(name, subdir)
+ if isVendoredPackage(name) {
+ continue
+ }
+ if inSubmodule(zf.Name) {
+ continue
+ }
+ base := path.Base(name)
+ if strings.ToLower(base) == "go.mod" && base != "go.mod" {
+ return "", fmt.Errorf("zip file contains %s, want all lower-case go.mod", zf.Name)
+ }
+ if name == "LICENSE" {
+ haveLICENSE = true
+ }
+ size := int64(zf.UncompressedSize)
+ if size < 0 || maxSize < size {
+ return "", fmt.Errorf("module source tree too big")
+ }
+ maxSize -= size
+
+ rc, err := zf.Open()
+ if err != nil {
+ return "", err
+ }
+ w, err := zw.Create(r.modPrefix(version) + "/" + name)
+ lr := &io.LimitedReader{R: rc, N: size + 1}
+ if _, err := io.Copy(w, lr); err != nil {
+ return "", err
+ }
+ if lr.N <= 0 {
+ return "", fmt.Errorf("individual file too large")
+ }
+ }
+
+ if !haveLICENSE && subdir != "" {
+ if data, err := r.code.ReadFile(rev, "LICENSE", codehost.MaxLICENSE); err == nil {
+ w, err := zw.Create(r.modPrefix(version) + "/LICENSE")
+ if err != nil {
+ return "", err
+ }
+ if _, err := w.Write(data); err != nil {
+ return "", err
+ }
+ }
+ }
+ if err := zw.Close(); err != nil {
+ return "", err
+ }
+ if err := f2.Close(); err != nil {
+ return "", err
+ }
+
+ return f2.Name(), nil
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+ }
+}
+
+func isVendoredPackage(name string) bool {
+ var i int
+ if strings.HasPrefix(name, "vendor/") {
+ i += len("vendor/")
+ } else if j := strings.Index(name, "/vendor/"); j >= 0 {
+ i += len("/vendor/")
+ } else {
+ return false
+ }
+ return strings.Contains(name[i:], "/")
+}
+
+func PseudoVersion(major string, t time.Time, rev string) string {
+ if major == "" {
+ major = "v0"
+ }
+ return fmt.Sprintf("%s.0.0-%s-%s", major, t.UTC().Format("20060102150405"), rev)
+}
+
+var ErrNotPseudoVersion = errors.New("not a pseudo-version")
+
+/*
+func ParsePseudoVersion(repo Repo, version string) (rev string, err error) {
+ major := semver.Major(version)
+ if major == "" {
+ return "", ErrNotPseudoVersion
+ }
+ majorPrefix := major + ".0.0-"
+ if !strings.HasPrefix(version, majorPrefix) || !strings.Contains(version[len(majorPrefix):], "-") {
+ return "", ErrNotPseudoVersion
+ }
+ versionSuffix := version[len(majorPrefix):]
+ for i := 0; versionSuffix[i] != '-'; i++ {
+ c := versionSuffix[i]
+ if c < '0' || '9' < c {
+ return "", ErrNotPseudoVersion
+ }
+ }
+ rev = versionSuffix[strings.Index(versionSuffix, "-")+1:]
+ if rev == "" {
+ return "", ErrNotPseudoVersion
+ }
+ if proxyURL != "" {
+ return version, nil
+ }
+ fullRev, t, err := repo.CommitInfo(rev)
+ if err != nil {
+ return "", fmt.Errorf("unknown pseudo-version %s: loading %v: %v", version, rev, err)
+ }
+ v := PseudoVersion(major, t, repo.ShortRev(fullRev))
+ if v != version {
+ return "", fmt.Errorf("unknown pseudo-version %s: %v is %v", version, rev, v)
+ }
+ return fullRev, nil
+}
+*/
+
+var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.0\.0-[0-9]{14}-[A-Za-z0-9]+$`)
+
+func isPseudoVersion(v string) bool {
+ return pseudoVersionRE.MatchString(v)
+}
diff --git a/src/cmd/go/internal/modfetch/coderepo_test.go b/src/cmd/go/internal/modfetch/coderepo_test.go
new file mode 100644
index 0000000000..e3b106e195
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/coderepo_test.go
@@ -0,0 +1,688 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "archive/zip"
+ "internal/testenv"
+ "io"
+ "io/ioutil"
+ "log"
+ "os"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "cmd/go/internal/modfetch/codehost"
+)
+
+func init() {
+ isTest = true
+}
+
+func TestMain(m *testing.M) {
+ os.Exit(testMain(m))
+}
+
+func testMain(m *testing.M) int {
+ dir, err := ioutil.TempDir("", "gitrepo-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ codehost.WorkRoot = dir
+ return m.Run()
+}
+
+var codeRepoTests = []struct {
+ path string
+ lookerr string
+ mpath string
+ rev string
+ err string
+ version string
+ name string
+ short string
+ time time.Time
+ gomod string
+ gomoderr string
+ zip []string
+ ziperr string
+}{
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v0.0.0",
+ version: "v0.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.0",
+ version: "v2.0.0",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ ziperr: "missing go.mod",
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "80d85",
+ version: "v0.0.0-20180219231006-80d85c5d4d17",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "mytag",
+ version: "v0.0.0-20180219231006-80d85c5d4d17",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "80d85",
+ version: "v2.0.0-20180219231006-80d85c5d4d17",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ gomoderr: "missing go.mod",
+ ziperr: "missing go.mod",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v54321",
+ rev: "80d85",
+ version: "v54321.0.0-20180219231006-80d85c5d4d17",
+ name: "80d85c5d4d17598a0e9055e7c175a32b415d6128",
+ short: "80d85c5d4d17",
+ time: time.Date(2018, 2, 19, 23, 10, 6, 0, time.UTC),
+ ziperr: "missing go.mod",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.0",
+ err: "unknown revision \"submod/v1.0.0\"",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.3",
+ err: "unknown revision \"submod/v1.0.3\"",
+ },
+ {
+ path: "github.com/rsc/vgotest1/submod",
+ rev: "v1.0.4",
+ version: "v1.0.4",
+ name: "8afe2b2efed96e0880ecd2a69b98a53b8c2738b6",
+ short: "8afe2b2efed9",
+ time: time.Date(2018, 2, 19, 23, 12, 7, 0, time.UTC),
+ gomod: "module \"github.com/vgotest1/submod\" // submod/go.mod\n",
+ zip: []string{
+ "go.mod",
+ "pkg/p.go",
+ "LICENSE",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ rev: "v1.1.0",
+ version: "v1.1.0",
+ name: "b769f2de407a4db81af9c5de0a06016d60d2ea09",
+ short: "b769f2de407a",
+ time: time.Date(2018, 2, 19, 23, 13, 36, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1\" // root go.mod\nrequire \"github.com/rsc/vgotest1/submod\" v1.0.5\n",
+ zip: []string{
+ "LICENSE",
+ "README.md",
+ "go.mod",
+ "pkg/p.go",
+ },
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.1",
+ version: "v2.0.1",
+ name: "ea65f87c8f52c15ea68f3bdd9925ef17e20d91e9",
+ short: "ea65f87c8f52",
+ time: time.Date(2018, 2, 19, 23, 14, 23, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1/v2\" // root go.mod\n",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.3",
+ version: "v2.0.3",
+ name: "f18795870fb14388a21ef3ebc1d75911c8694f31",
+ short: "f18795870fb1",
+ time: time.Date(2018, 2, 19, 23, 16, 4, 0, time.UTC),
+ gomoderr: "v2/go.mod has non-.../v2 module path",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.4",
+ version: "v2.0.4",
+ name: "1f863feb76bc7029b78b21c5375644838962f88d",
+ short: "1f863feb76bc",
+ time: time.Date(2018, 2, 20, 0, 3, 38, 0, time.UTC),
+ gomoderr: "both go.mod and v2/go.mod claim .../v2 module",
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ rev: "v2.0.5",
+ version: "v2.0.5",
+ name: "2f615117ce481c8efef46e0cc0b4b4dccfac8fea",
+ short: "2f615117ce48",
+ time: time.Date(2018, 2, 20, 0, 3, 59, 0, time.UTC),
+ gomod: "module \"github.com/rsc/vgotest1/v2\" // v2/go.mod\n",
+ },
+ {
+ path: "go.googlesource.com/scratch",
+ rev: "0f302529858",
+ version: "v0.0.0-20180220024720-0f3025298580",
+ name: "0f30252985809011f026b5a2d5cf456e021623da",
+ short: "0f3025298580",
+ time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule go.googlesource.com/scratch\n",
+ },
+ {
+ path: "go.googlesource.com/scratch/rsc",
+ rev: "0f302529858",
+ version: "v0.0.0-20180220024720-0f3025298580",
+ name: "0f30252985809011f026b5a2d5cf456e021623da",
+ short: "0f3025298580",
+ time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC),
+ gomod: "",
+ },
+ {
+ path: "go.googlesource.com/scratch/cbro",
+ rev: "0f302529858",
+ version: "v0.0.0-20180220024720-0f3025298580",
+ name: "0f30252985809011f026b5a2d5cf456e021623da",
+ short: "0f3025298580",
+ time: time.Date(2018, 2, 20, 2, 47, 20, 0, time.UTC),
+ gomoderr: "missing go.mod",
+ },
+ {
+ // redirect to github
+ path: "rsc.io/quote",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ name: "f488df80bcdbd3e5bafdc24ad7d1e79e83edd7e6",
+ short: "f488df80bcdb",
+ time: time.Date(2018, 2, 14, 0, 45, 20, 0, time.UTC),
+ gomod: "module \"rsc.io/quote\"\n",
+ },
+ {
+ // redirect to static hosting proxy
+ path: "swtch.com/testmod",
+ rev: "v1.0.0",
+ version: "v1.0.0",
+ name: "v1.0.0",
+ short: "v1.0.0",
+ time: time.Date(1972, 7, 18, 12, 34, 56, 0, time.UTC),
+ gomod: "module \"swtch.com/testmod\"\n",
+ },
+ {
+ // redirect to googlesource
+ path: "golang.org/x/text",
+ rev: "4e4a3210bb",
+ version: "v0.0.0-20180208041248-4e4a3210bb54",
+ name: "4e4a3210bb54bb31f6ab2cdca2edcc0b50c420c1",
+ short: "4e4a3210bb54",
+ time: time.Date(2018, 2, 8, 4, 12, 48, 0, time.UTC),
+ },
+ {
+ path: "github.com/pkg/errors",
+ rev: "v0.8.0",
+ version: "v0.8.0",
+ name: "645ef00459ed84a119197bfb8d8205042c6df63d",
+ short: "645ef00459ed",
+ time: time.Date(2016, 9, 29, 1, 48, 1, 0, time.UTC),
+ },
+ {
+ // package in subdirectory - custom domain
+ path: "golang.org/x/net/context",
+ lookerr: "module root is \"golang.org/x/net\"",
+ },
+ {
+ // package in subdirectory - github
+ path: "github.com/rsc/quote/buggy",
+ rev: "c4d4236f",
+ version: "v0.0.0-20180214154420-c4d4236f9242",
+ name: "c4d4236f92427c64bfbcf1cc3f8142ab18f30b22",
+ short: "c4d4236f9242",
+ time: time.Date(2018, 2, 14, 15, 44, 20, 0, time.UTC),
+ gomoderr: "missing go.mod",
+ },
+ {
+ path: "gopkg.in/yaml.v2",
+ rev: "d670f940",
+ version: "v2.0.0-20180109114331-d670f9405373",
+ name: "d670f9405373e636a5a2765eea47fac0c9bc91a4",
+ short: "d670f9405373",
+ time: time.Date(2018, 1, 9, 11, 43, 31, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule gopkg.in/yaml.v2\n",
+ },
+ {
+ path: "gopkg.in/check.v1",
+ rev: "20d25e280405",
+ version: "v1.0.0-20161208181325-20d25e280405",
+ name: "20d25e2804050c1cd24a7eea1e7a6447dd0e74ec",
+ short: "20d25e280405",
+ time: time.Date(2016, 12, 8, 18, 13, 25, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule gopkg.in/check.v1\n",
+ },
+ {
+ path: "gopkg.in/yaml.v2",
+ rev: "v2",
+ version: "v2.0.0-20180328195020-5420a8b6744d",
+ name: "5420a8b6744d3b0345ab293f6fcba19c978f1183",
+ short: "5420a8b6744d",
+ time: time.Date(2018, 3, 28, 19, 50, 20, 0, time.UTC),
+ gomod: "module \"gopkg.in/yaml.v2\"\n\nrequire (\n\t\"gopkg.in/check.v1\" v0.0.0-20161208181325-20d25e280405\n)\n",
+ },
+ {
+ path: "vcs-test.golang.org/go/mod/gitrepo1",
+ rev: "master",
+ version: "v0.0.0-20180417194322-ede458df7cd0",
+ name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ short: "ede458df7cd0",
+ time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule vcs-test.golang.org/go/mod/gitrepo1\n",
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ rev: "latest",
+ version: "v2.0.0-20170531160350-a96e63847dc3",
+ name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
+ short: "a96e63847dc3",
+ time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule gopkg.in/natefinch/lumberjack.v2\n",
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ // This repo has a v2.1 tag.
+ // We only allow semver references to tags that are fully qualified, as in v2.1.0.
+ // Because we can't record v2.1.0 (the actual tag is v2.1), we record a pseudo-version
+ // instead, same as if the tag were any other non-version-looking string.
+ // We use a v2 pseudo-version here because of the .v2 in the path, not because
+ // of the v2 in the rev.
+ rev: "v2.1", // non-canonical semantic version turns into pseudo-version
+ version: "v2.0.0-20170531160350-a96e63847dc3",
+ name: "a96e63847dc3c67d17befa69c303767e2f84e54f",
+ short: "a96e63847dc3",
+ time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
+ gomod: "//vgo 0.0.4\n\nmodule gopkg.in/natefinch/lumberjack.v2\n",
+ },
+}
+
+func TestCodeRepo(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range codeRepoTests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"/"+tt.rev, func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ if tt.lookerr != "" {
+ if err.Error() == tt.lookerr {
+ return
+ }
+ t.Errorf("Lookup(%q): %v, want error %q", tt.path, err, tt.lookerr)
+ }
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ if tt.mpath == "" {
+ tt.mpath = tt.path
+ }
+ if mpath := repo.ModulePath(); mpath != tt.mpath {
+ t.Errorf("repo.ModulePath() = %q, want %q", mpath, tt.mpath)
+ }
+ info, err := repo.Stat(tt.rev)
+ if err != nil {
+ if tt.err != "" {
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("repoStat(%q): %v, wanted %q", tt.rev, err, tt.err)
+ }
+ return
+ }
+ t.Fatalf("repo.Stat(%q): %v", tt.rev, err)
+ }
+ if tt.err != "" {
+ t.Errorf("repo.Stat(%q): success, wanted error", tt.rev)
+ }
+ if info.Version != tt.version {
+ t.Errorf("info.Version = %q, want %q", info.Version, tt.version)
+ }
+ if info.Name != tt.name {
+ t.Errorf("info.Name = %q, want %q", info.Name, tt.name)
+ }
+ if info.Short != tt.short {
+ t.Errorf("info.Short = %q, want %q", info.Short, tt.short)
+ }
+ if !info.Time.Equal(tt.time) {
+ t.Errorf("info.Time = %v, want %v", info.Time, tt.time)
+ }
+ if tt.gomod != "" || tt.gomoderr != "" {
+ data, err := repo.GoMod(tt.version)
+ if err != nil && tt.gomoderr == "" {
+ t.Errorf("repo.GoMod(%q): %v", tt.version, err)
+ } else if err != nil && tt.gomoderr != "" {
+ if err.Error() != tt.gomoderr {
+ t.Errorf("repo.GoMod(%q): %v, want %q", tt.version, err, tt.gomoderr)
+ }
+ } else if tt.gomoderr != "" {
+ t.Errorf("repo.GoMod(%q) = %q, want error %q", tt.version, data, tt.gomoderr)
+ } else if string(data) != tt.gomod {
+ t.Errorf("repo.GoMod(%q) = %q, want %q", tt.version, data, tt.gomod)
+ }
+ }
+ if tt.zip != nil || tt.ziperr != "" {
+ zipfile, err := repo.Zip(tt.version, tmpdir)
+ if err != nil {
+ if tt.ziperr != "" {
+ if err.Error() == tt.ziperr {
+ return
+ }
+ t.Fatalf("repo.Zip(%q): %v, want error %q", tt.version, err, tt.ziperr)
+ }
+ t.Fatalf("repo.Zip(%q): %v", tt.version, err)
+ }
+ if tt.ziperr != "" {
+ t.Errorf("repo.Zip(%q): success, want error %q", tt.version, tt.ziperr)
+ }
+ prefix := tt.path + "@" + tt.version + "/"
+ z, err := zip.OpenReader(zipfile)
+ if err != nil {
+ t.Fatalf("open zip %s: %v", zipfile, err)
+ }
+ var names []string
+ for _, file := range z.File {
+ if !strings.HasPrefix(file.Name, prefix) {
+ t.Errorf("zip entry %v does not start with prefix %v", file.Name, prefix)
+ continue
+ }
+ names = append(names, file.Name[len(prefix):])
+ }
+ z.Close()
+ if !reflect.DeepEqual(names, tt.zip) {
+ t.Fatalf("zip = %v\nwant %v\n", names, tt.zip)
+ }
+ }
+ })
+ }
+}
+
+var importTests = []struct {
+ path string
+ mpath string
+ err string
+}{
+ {
+ path: "golang.org/x/net/context",
+ mpath: "golang.org/x/net",
+ },
+ {
+ path: "github.com/rsc/quote/buggy",
+ mpath: "github.com/rsc/quote",
+ },
+ {
+ path: "golang.org/x/net",
+ mpath: "golang.org/x/net",
+ },
+ {
+ path: "github.com/rsc/quote",
+ mpath: "github.com/rsc/quote",
+ },
+ {
+ path: "golang.org/x/foo/bar",
+ err: "unknown module golang.org/x/foo/bar: no go-import tags",
+ },
+}
+
+func TestImport(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ for _, tt := range importTests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ repo, info, err := Import(tt.path, nil)
+ if err != nil {
+ if tt.err != "" {
+ if err.Error() == tt.err {
+ return
+ }
+ t.Errorf("Import(%q): %v, want error %q", tt.path, err, tt.err)
+ }
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ if mpath := repo.ModulePath(); mpath != tt.mpath {
+ t.Errorf("repo.ModulePath() = %q (%v), want %q", mpath, info.Version, tt.mpath)
+ }
+ })
+ }
+}
+
+var codeRepoVersionsTests = []struct {
+ path string
+ prefix string
+ versions []string
+}{
+ // TODO: Why do we allow a prefix here at all?
+ {
+ path: "github.com/rsc/vgotest1",
+ versions: []string{"v0.0.0", "v0.0.1", "v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3", "v1.1.0"},
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ prefix: "v1.0",
+ versions: []string{"v1.0.0", "v1.0.1", "v1.0.2", "v1.0.3"},
+ },
+ {
+ path: "github.com/rsc/vgotest1/v2",
+ versions: []string{"v2.0.0", "v2.0.1", "v2.0.2", "v2.0.3", "v2.0.4", "v2.0.5", "v2.0.6"},
+ },
+ {
+ path: "swtch.com/testmod",
+ versions: []string{"v1.0.0", "v1.1.1"},
+ },
+ {
+ path: "gopkg.in/russross/blackfriday.v2",
+ versions: []string{"v2.0.0"},
+ },
+ {
+ path: "gopkg.in/natefinch/lumberjack.v2",
+ versions: []string{},
+ },
+}
+
+func TestCodeRepoVersions(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range codeRepoVersionsTests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1), func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ list, err := repo.Versions(tt.prefix)
+ if err != nil {
+ t.Fatalf("Versions(%q): %v", tt.prefix, err)
+ }
+ if !reflect.DeepEqual(list, tt.versions) {
+ t.Fatalf("Versions(%q):\nhave %v\nwant %v", tt.prefix, list, tt.versions)
+ }
+ })
+ }
+}
+
+var latestTests = []struct {
+ path string
+ version string
+ err string
+}{
+ {
+ path: "github.com/rsc/empty",
+ err: "no commits",
+ },
+ {
+ path: "github.com/rsc/vgotest1",
+ version: "v0.0.0-20180219223237-a08abb797a67",
+ },
+ {
+ path: "swtch.com/testmod",
+ version: "v1.1.1",
+ },
+}
+
+func TestLatest(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ tmpdir, err := ioutil.TempDir("", "vgo-modfetch-test-")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+ for _, tt := range latestTests {
+ name := strings.Replace(tt.path, "/", "_", -1)
+ t.Run(name, func(t *testing.T) {
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ t.Fatalf("Lookup(%q): %v", tt.path, err)
+ }
+ info, err := repo.Latest()
+ if err != nil {
+ if tt.err != "" {
+ if err.Error() == tt.err {
+ return
+ }
+ t.Fatalf("Latest(): %v, want %q", err, tt.err)
+ }
+ t.Fatalf("Latest(): %v", err)
+ }
+ if info.Version != tt.version {
+ t.Fatalf("Latest() = %v, want %v", info.Version, tt.version)
+ }
+ })
+ }
+}
+
+// fixedTagsRepo is a fake codehost.Repo that returns a fixed list of tags
+type fixedTagsRepo struct {
+ root string
+ tags []string
+}
+
+func (ch *fixedTagsRepo) Tags(string) ([]string, error) { return ch.tags, nil }
+func (ch *fixedTagsRepo) Root() string { return ch.root }
+func (ch *fixedTagsRepo) Latest() (*codehost.RevInfo, error) { panic("not impl") }
+func (ch *fixedTagsRepo) ReadFile(string, string, int64) ([]byte, error) { panic("not impl") }
+func (ch *fixedTagsRepo) ReadZip(string, string, int64) (io.ReadCloser, string, error) {
+ panic("not impl")
+}
+func (ch *fixedTagsRepo) Stat(string) (*codehost.RevInfo, error) { panic("not impl") }
+
+func TestNonCanonicalSemver(t *testing.T) {
+ root := "golang.org/x/issue24476"
+ ch := &fixedTagsRepo{
+ root: root,
+ tags: []string{
+ "", "huh?", "1.0.1",
+ // what about "version 1 dot dogcow"?
+ "v1.🐕.🐄",
+ "v1", "v0.1",
+ // and one normal one that should pass through
+ "v1.0.1",
+ },
+ }
+
+ cr, err := newCodeRepo(ch, root)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ v, err := cr.Versions("")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(v) != 1 || v[0] != "v1.0.1" {
+ t.Fatal("unexpected versions returned:", v)
+ }
+}
+
+var modPathTests = []struct {
+ input []byte
+ expected string
+}{
+ {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module \"github.com/rsc/vgotest\""), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module github.com/rsc/vgotest"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module `github.com/rsc/vgotest`"), expected: "github.com/rsc/vgotest"},
+ {input: []byte("module \"github.com/rsc/vgotest/v2\""), expected: "github.com/rsc/vgotest/v2"},
+ {input: []byte("module github.com/rsc/vgotest/v2"), expected: "github.com/rsc/vgotest/v2"},
+ {input: []byte("module \"gopkg.in/yaml.v2\""), expected: "gopkg.in/yaml.v2"},
+ {input: []byte("module gopkg.in/yaml.v2"), expected: "gopkg.in/yaml.v2"},
+ {input: []byte("module \"gopkg.in/check.v1\"\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\n\""), expected: ""},
+ {input: []byte("module gopkg.in/check.v1\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\"\r\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module gopkg.in/check.v1\r\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \"gopkg.in/check.v1\"\n\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module gopkg.in/check.v1\n\n"), expected: "gopkg.in/check.v1"},
+ {input: []byte("module \n\"gopkg.in/check.v1\"\n\n"), expected: ""},
+ {input: []byte("module \ngopkg.in/check.v1\n\n"), expected: ""},
+ {input: []byte("module \"gopkg.in/check.v1\"asd"), expected: ""},
+}
+
+func TestModPath(t *testing.T) {
+ for _, test := range modPathTests {
+ t.Run(string(test.input), func(t *testing.T) {
+ result := modPath(test.input)
+ if result != test.expected {
+ t.Fatalf("modPath(%s): %s, want %s", string(test.input), result, test.expected)
+ }
+ })
+ }
+}
diff --git a/src/cmd/go/internal/modfetch/convert.go b/src/cmd/go/internal/modfetch/convert.go
new file mode 100644
index 0000000000..5c482be003
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/convert.go
@@ -0,0 +1,78 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "fmt"
+ "os"
+ "sort"
+ "strings"
+
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/semver"
+)
+
+// ConvertLegacyConfig converts legacy config to modfile.
+// The file argument is slash-delimited.
+func ConvertLegacyConfig(f *modfile.File, file string, data []byte) error {
+ i := strings.LastIndex(file, "/")
+ j := -2
+ if i >= 0 {
+ j = strings.LastIndex(file[:i], "/")
+ }
+ convert := modconv.Converters[file[i+1:]]
+ if convert == nil && j != -2 {
+ convert = modconv.Converters[file[j+1:]]
+ }
+ if convert == nil {
+ return fmt.Errorf("unknown legacy config file %s", file)
+ }
+ require, err := convert(file, data)
+ if err != nil {
+ return fmt.Errorf("parsing %s: %v", file, err)
+ }
+
+ // Convert requirements block, which may use raw SHA1 hashes as versions,
+ // to valid semver requirement list, respecting major versions.
+ need := make(map[string]string)
+ for _, r := range require {
+ if r.Path == "" {
+ continue
+ }
+
+ // TODO: Something better here.
+ if strings.HasPrefix(r.Path, "github.com/") || strings.HasPrefix(r.Path, "golang.org/x/") {
+ f := strings.Split(r.Path, "/")
+ if len(f) > 3 {
+ r.Path = strings.Join(f[:3], "/")
+ }
+ }
+
+ repo, err := Lookup(r.Path)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "vgo: lookup %s: %v\n", r.Path, err)
+ continue
+ }
+ info, err := repo.Stat(r.Version)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "vgo: stat %s@%s: %v\n", r.Path, r.Version, err)
+ continue
+ }
+ path := repo.ModulePath()
+ need[path] = semver.Max(need[path], info.Version)
+ }
+
+ var paths []string
+ for path := range need {
+ paths = append(paths, path)
+ }
+ sort.Strings(paths)
+ for _, path := range paths {
+ f.AddRequire(path, need[path])
+ }
+
+ return nil
+}
diff --git a/src/cmd/go/internal/modfetch/convert_test.go b/src/cmd/go/internal/modfetch/convert_test.go
new file mode 100644
index 0000000000..03ae1569f0
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/convert_test.go
@@ -0,0 +1,139 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "bytes"
+ "internal/testenv"
+ "strings"
+ "testing"
+
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfile"
+)
+
+func TestConvertLegacyConfig(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ if testing.Verbose() {
+ old := cfg.BuildX
+ defer func() {
+ cfg.BuildX = old
+ }()
+ cfg.BuildX = true
+ }
+
+ var tests = []struct {
+ path string
+ vers string
+ gomod string
+ }{
+ {
+ // Gopkg.lock parsing.
+ "github.com/golang/dep", "v0.4.0",
+ `module github.com/golang/dep
+
+ require (
+ github.com/Masterminds/semver v0.0.0-20170726230514-a93e51b5a57e
+ github.com/Masterminds/vcs v1.11.1
+ github.com/armon/go-radix v0.0.0-20160115234725-4239b77079c7
+ github.com/boltdb/bolt v1.3.1
+ github.com/go-yaml/yaml v0.0.0-20170407172122-cd8b52f8269e
+ github.com/golang/protobuf v0.0.0-20170901042739-5afd06f9d81a
+ github.com/jmank88/nuts v0.3.0
+ github.com/nightlyone/lockfile v0.0.0-20170707060451-e83dc5e7bba0
+ github.com/pelletier/go-toml v0.0.0-20171218135716-b8b5e7696574
+ github.com/pkg/errors v0.8.0
+ github.com/sdboyer/constext v0.0.0-20170321163424-836a14457353
+ golang.org/x/net v0.0.0-20170828231752-66aacef3dd8a
+ golang.org/x/sync v0.0.0-20170517211232-f52d1811a629
+ golang.org/x/sys v0.0.0-20170830134202-bb24a47a89ea
+ )`,
+ },
+
+ // TODO: https://github.com/docker/distribution uses vendor.conf
+
+ {
+ // Godeps.json parsing.
+ // TODO: Should v2.0.0 work here too?
+ "github.com/docker/distribution", "v0.0.0-20150410205453-85de3967aa93",
+ `module github.com/docker/distribution
+
+ require (
+ github.com/AdRoll/goamz v0.0.0-20150130162828-d3664b76d905
+ github.com/MSOpenTech/azure-sdk-for-go v0.0.0-20150323223030-d90753bcad2e
+ github.com/Sirupsen/logrus v0.0.0-20150409230825-55eb11d21d2a
+ github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd
+ github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b
+ github.com/bugsnag/panicwrap v0.0.0-20141110184334-e5f9854865b9
+ github.com/codegangsta/cli v0.0.0-20150131031259-6086d7927ec3
+ github.com/docker/docker v0.0.0-20150204013315-165ea5c158cf
+ github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1
+ github.com/garyburd/redigo v0.0.0-20150301180006-535138d7bcd7
+ github.com/gorilla/context v0.0.0-20140604161150-14f550f51af5
+ github.com/gorilla/handlers v0.0.0-20140825150757-0e84b7d810c1
+ github.com/gorilla/mux v0.0.0-20140926153814-e444e69cbd2e
+ github.com/jlhawn/go-crypto v0.0.0-20150401213827-cd738dde20f0
+ github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43
+ github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50
+ github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f
+ golang.org/x/net v0.0.0-20150202051010-1dfe7915deaf
+ gopkg.in/check.v1 v1.0.0-20141024133853-64131543e789
+ gopkg.in/yaml.v2 v2.0.0-20150116202057-bef53efd0c76
+ )`,
+ },
+
+ {
+ // golang.org/issue/24585 - confusion about v2.0.0 tag in legacy non-v2 module
+ "github.com/fishy/gcsbucket", "v0.0.0-20150410205453-618d60fe84e0",
+ `module github.com/fishy/gcsbucket
+
+ require (
+ cloud.google.com/go v0.18.0
+ github.com/fishy/fsdb v0.0.0-20180217030800-5527ded01371
+ github.com/golang/protobuf v1.0.0
+ github.com/googleapis/gax-go v0.0.0-20170915024731-317e0006254c
+ golang.org/x/net v0.0.0-20180216171745-136a25c244d3
+ golang.org/x/oauth2 v0.0.0-20180207181906-543e37812f10
+ golang.org/x/text v0.0.0-20180208041248-4e4a3210bb54
+ google.golang.org/api v0.0.0-20180217000815-c7a403bb5fe1
+ google.golang.org/appengine v1.0.0
+ google.golang.org/genproto v0.0.0-20180206005123-2b5a72b8730b
+ google.golang.org/grpc v1.10.0
+ )`,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(strings.Replace(tt.path, "/", "_", -1)+"_"+tt.vers, func(t *testing.T) {
+ f, err := modfile.Parse("golden", []byte(tt.gomod), nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ want, err := f.Format()
+ if err != nil {
+ t.Fatal(err)
+ }
+ repo, err := Lookup(tt.path)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ out, err := repo.GoMod(tt.vers)
+ if err != nil {
+ t.Fatal(err)
+ }
+ prefix := modconv.Prefix + "\n"
+ if !bytes.HasPrefix(out, []byte(prefix)) {
+ t.Fatalf("go.mod missing prefix %q:\n%s", prefix, out)
+ }
+ out = out[len(prefix):]
+ if !bytes.Equal(out, want) {
+ t.Fatalf("final go.mod:\n%s\n\nwant:\n%s", out, want)
+ }
+ })
+ }
+}
diff --git a/src/cmd/go/internal/modfetch/domain.go b/src/cmd/go/internal/modfetch/domain.go
new file mode 100644
index 0000000000..2494f80ab0
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/domain.go
@@ -0,0 +1,178 @@
+// Copyright 2018 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.
+
+// Support for custom domains.
+
+package modfetch
+
+import (
+ "encoding/xml"
+ "fmt"
+ "io"
+ "net/url"
+ "os"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/gitrepo"
+)
+
+// metaImport represents the parsed <meta name="go-import"
+// content="prefix vcs reporoot" /> tags from HTML files.
+type metaImport struct {
+ Prefix, VCS, RepoRoot string
+}
+
+func lookupCustomDomain(path string) (Repo, error) {
+ dom := path
+ if i := strings.Index(dom, "/"); i >= 0 {
+ dom = dom[:i]
+ }
+ if !strings.Contains(dom, ".") {
+ return nil, fmt.Errorf("unknown module %s: not a domain name", path)
+ }
+ var body io.ReadCloser
+ err := webGetGoGet("https://"+path+"?go-get=1", &body)
+ if body != nil {
+ defer body.Close()
+ }
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "FindRepo: %v\n", err)
+ return nil, err
+ }
+ // Note: accepting a non-200 OK here, so people can serve a
+ // meta import in their http 404 page.
+ imports, err := parseMetaGoImports(body)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "findRepo: %v\n", err)
+ return nil, err
+ }
+ if len(imports) == 0 {
+ return nil, fmt.Errorf("unknown module %s: no go-import tags", path)
+ }
+
+ // First look for new module definition.
+ for _, imp := range imports {
+ if path == imp.Prefix || strings.HasPrefix(path, imp.Prefix+"/") {
+ if imp.VCS == "mod" {
+ u, err := url.Parse(imp.RepoRoot)
+ if err != nil {
+ return nil, fmt.Errorf("invalid module URL %q", imp.RepoRoot)
+ } else if u.Scheme != "https" {
+ // TODO: Allow -insecure flag as a build flag?
+ return nil, fmt.Errorf("invalid module URL %q: must be HTTPS", imp.RepoRoot)
+ }
+ return newProxyRepo(imp.RepoRoot, imp.Prefix), nil
+ }
+ }
+ }
+
+ // Fall back to redirections to known version control systems.
+ for _, imp := range imports {
+ if path == imp.Prefix {
+ if !strings.HasPrefix(imp.RepoRoot, "https://") {
+ // TODO: Allow -insecure flag as a build flag?
+ return nil, fmt.Errorf("invalid server URL %q: must be HTTPS", imp.RepoRoot)
+ }
+ if imp.VCS == "git" {
+ code, err := gitrepo.Repo(imp.RepoRoot, imp.Prefix)
+ if err != nil {
+ return nil, err
+ }
+ return newCodeRepo(code, path)
+ }
+ return nil, fmt.Errorf("unknown VCS, Repo: %s, %s", imp.VCS, imp.RepoRoot)
+ }
+ }
+
+ // Check for redirect to repo root.
+ for _, imp := range imports {
+ if strings.HasPrefix(path, imp.Prefix+"/") {
+ return nil, &ModuleSubdirError{imp.Prefix}
+ }
+ }
+
+ return nil, fmt.Errorf("unknown module %s: no matching go-import tags", path)
+}
+
+type ModuleSubdirError struct {
+ ModulePath string
+}
+
+func (e *ModuleSubdirError) Error() string {
+ return fmt.Sprintf("module root is %q", e.ModulePath)
+}
+
+type customPrefix struct {
+ codehost.Repo
+ root string
+}
+
+func (c *customPrefix) Root() string {
+ return c.root
+}
+
+// parseMetaGoImports returns meta imports from the HTML in r.
+// Parsing ends at the end of the <head> section or the beginning of the <body>.
+func parseMetaGoImports(r io.Reader) (imports []metaImport, err error) {
+ d := xml.NewDecoder(r)
+ d.CharsetReader = charsetReader
+ d.Strict = false
+ var t xml.Token
+ for {
+ t, err = d.RawToken()
+ if err != nil {
+ if err == io.EOF || len(imports) > 0 {
+ err = nil
+ }
+ return
+ }
+ if e, ok := t.(xml.StartElement); ok && strings.EqualFold(e.Name.Local, "body") {
+ return
+ }
+ if e, ok := t.(xml.EndElement); ok && strings.EqualFold(e.Name.Local, "head") {
+ return
+ }
+ e, ok := t.(xml.StartElement)
+ if !ok || !strings.EqualFold(e.Name.Local, "meta") {
+ continue
+ }
+ if attrValue(e.Attr, "name") != "go-import" {
+ continue
+ }
+ if f := strings.Fields(attrValue(e.Attr, "content")); len(f) == 3 {
+ imports = append(imports, metaImport{
+ Prefix: f[0],
+ VCS: f[1],
+ RepoRoot: f[2],
+ })
+ }
+ }
+}
+
+// attrValue returns the attribute value for the case-insensitive key
+// `name', or the empty string if nothing is found.
+func attrValue(attrs []xml.Attr, name string) string {
+ for _, a := range attrs {
+ if strings.EqualFold(a.Name.Local, name) {
+ return a.Value
+ }
+ }
+ return ""
+}
+
+// charsetReader returns a reader for the given charset. Currently
+// it only supports UTF-8 and ASCII. Otherwise, it returns a meaningful
+// error which is printed by go get, so the user can find why the package
+// wasn't downloaded if the encoding is not supported. Note that, in
+// order to reduce potential errors, ASCII is treated as UTF-8 (i.e. characters
+// greater than 0x7f are not rejected).
+func charsetReader(charset string, input io.Reader) (io.Reader, error) {
+ switch strings.ToLower(charset) {
+ case "ascii":
+ return input, nil
+ default:
+ return nil, fmt.Errorf("can't decode XML document using charset %q", charset)
+ }
+}
diff --git a/src/cmd/go/internal/modfetch/github/fetch.go b/src/cmd/go/internal/modfetch/github/fetch.go
new file mode 100644
index 0000000000..a2a90f166c
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/github/fetch.go
@@ -0,0 +1,24 @@
+// Copyright 2018 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 github
+
+import (
+ "fmt"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/gitrepo"
+)
+
+// Lookup returns the code repository enclosing the given module path,
+// which must begin with github.com/.
+func Lookup(path string) (codehost.Repo, error) {
+ f := strings.Split(path, "/")
+ if len(f) < 3 || f[0] != "github.com" {
+ return nil, fmt.Errorf("github repo must be github.com/org/project")
+ }
+ path = f[0] + "/" + f[1] + "/" + f[2]
+ return gitrepo.Repo("https://"+path, path)
+}
diff --git a/src/cmd/go/internal/modfetch/gitrepo/fetch.go b/src/cmd/go/internal/modfetch/gitrepo/fetch.go
new file mode 100644
index 0000000000..0d6eb4b7e9
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/gitrepo/fetch.go
@@ -0,0 +1,445 @@
+// Copyright 2018 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 gitrepo provides a Git-based implementation of codehost.Repo.
+package gitrepo
+
+import (
+ "archive/zip"
+ "bytes"
+ "cmd/go/internal/modfetch/codehost"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "time"
+)
+
+// Repo returns the code repository at the given Git remote reference.
+// The returned repo reports the given root as its module root.
+func Repo(remote, root string) (codehost.Repo, error) {
+ return newRepo(remote, root, false)
+}
+
+// LocalRepo is like Repo but accepts both Git remote references
+// and paths to repositories on the local file system.
+// The returned repo reports the given root as its module root.
+func LocalRepo(remote, root string) (codehost.Repo, error) {
+ return newRepo(remote, root, true)
+}
+
+const workDirType = "git2"
+
+func newRepo(remote, root string, localOK bool) (codehost.Repo, error) {
+ r := &repo{remote: remote, root: root, canArchive: true}
+ if strings.Contains(remote, "://") {
+ // This is a remote path.
+ dir, err := codehost.WorkDir(workDirType, r.remote)
+ if err != nil {
+ return nil, err
+ }
+ r.dir = dir
+ if _, err := os.Stat(filepath.Join(dir, "objects")); err != nil {
+ if _, err := codehost.Run(dir, "git", "init", "--bare"); err != nil {
+ os.RemoveAll(dir)
+ return nil, err
+ }
+ // We could just say git fetch https://whatever later,
+ // but this lets us say git fetch origin instead, which
+ // is a little nicer. More importantly, using a named remote
+ // avoids a problem with Git LFS. See golang.org/issue/25605.
+ if _, err := codehost.Run(dir, "git", "remote", "add", "origin", r.remote); err != nil {
+ os.RemoveAll(dir)
+ return nil, err
+ }
+ r.remote = "origin"
+ }
+ } else {
+ // Local path.
+ // Disallow colon (not in ://) because sometimes
+ // that's rcp-style host:path syntax and sometimes it's not (c:\work).
+ // The go command has always insisted on URL syntax for ssh.
+ if strings.Contains(remote, ":") {
+ return nil, fmt.Errorf("git remote cannot use host:path syntax")
+ }
+ if !localOK {
+ return nil, fmt.Errorf("git remote must not be local directory")
+ }
+ r.local = true
+ info, err := os.Stat(remote)
+ if err != nil {
+ return nil, err
+ }
+ if !info.IsDir() {
+ return nil, fmt.Errorf("%s exists but is not a directory", remote)
+ }
+ r.dir = remote
+ }
+ return r, nil
+}
+
+type repo struct {
+ remote string
+ local bool
+ root string
+ dir string
+ canArchive bool
+
+ refsOnce sync.Once
+ refs map[string]string
+ refsErr error
+}
+
+func (r *repo) Root() string {
+ return r.root
+}
+
+// loadRefs loads heads and tags references from the remote into the map r.refs.
+// Should only be called as r.refsOnce.Do(r.loadRefs).
+func (r *repo) loadRefs() {
+ // The git protocol sends all known refs and ls-remote filters them on the client side,
+ // so we might as well record both heads and tags in one shot.
+ // Most of the time we only care about tags but sometimes we care about heads too.
+ out, err := codehost.Run(r.dir, "git", "ls-remote", "-q", r.remote)
+ if err != nil {
+ r.refsErr = err
+ return
+ }
+
+ r.refs = make(map[string]string)
+ for _, line := range strings.Split(string(out), "\n") {
+ f := strings.Fields(line)
+ if len(f) != 2 {
+ continue
+ }
+ if f[1] == "HEAD" || strings.HasPrefix(f[1], "refs/heads/") || strings.HasPrefix(f[1], "refs/tags/") {
+ r.refs[f[1]] = f[0]
+ }
+ }
+ for ref, hash := range r.refs {
+ if strings.HasSuffix(ref, "^{}") { // record unwrapped annotated tag as value of tag
+ r.refs[strings.TrimSuffix(ref, "^{}")] = hash
+ delete(r.refs, ref)
+ }
+ }
+}
+
+func (r *repo) Tags(prefix string) ([]string, error) {
+ r.refsOnce.Do(r.loadRefs)
+ if r.refsErr != nil {
+ return nil, r.refsErr
+ }
+
+ tags := []string{}
+ for ref := range r.refs {
+ if !strings.HasPrefix(ref, "refs/tags/") {
+ continue
+ }
+ tag := ref[len("refs/tags/"):]
+ if !strings.HasPrefix(tag, prefix) {
+ continue
+ }
+ tags = append(tags, tag)
+ }
+ sort.Strings(tags)
+ return tags, nil
+}
+
+func (r *repo) Latest() (*codehost.RevInfo, error) {
+ r.refsOnce.Do(r.loadRefs)
+ if r.refsErr != nil {
+ return nil, r.refsErr
+ }
+ if r.refs["HEAD"] == "" {
+ return nil, fmt.Errorf("no commits")
+ }
+ return r.Stat(r.refs["HEAD"])
+}
+
+// findRef finds some ref name for the given hash,
+// for use when the server requires giving a ref instead of a hash.
+// There may be multiple ref names for a given hash,
+// in which case this returns some name - it doesn't matter which.
+func (r *repo) findRef(hash string) (ref string, ok bool) {
+ r.refsOnce.Do(r.loadRefs)
+ for ref, h := range r.refs {
+ if h == hash {
+ return ref, true
+ }
+ }
+ return "", false
+}
+
+func unshallow(gitDir string) []string {
+ if _, err := os.Stat(filepath.Join(gitDir, "shallow")); err == nil {
+ return []string{"--unshallow"}
+ }
+ return []string{}
+}
+
+// statOrArchive tries to stat the given rev in the local repository,
+// or else it tries to obtain an archive at the rev with the given arguments,
+// or else it falls back to aggressive fetching and then a local stat.
+// The archive step is an optimization for servers that support it
+// (most do not, but maybe that will change), to let us minimize
+// the amount of code downloaded.
+func (r *repo) statOrArchive(rev string, archiveArgs ...string) (info *codehost.RevInfo, archive []byte, err error) {
+ // Do we have this rev?
+ r.refsOnce.Do(r.loadRefs)
+ var hash string
+ if k := "refs/tags/" + rev; r.refs[k] != "" {
+ hash = r.refs[k]
+ } else if k := "refs/heads/" + rev; r.refs[k] != "" {
+ hash = r.refs[k]
+ rev = hash
+ } else if rev == "HEAD" && r.refs["HEAD"] != "" {
+ hash = r.refs["HEAD"]
+ rev = hash
+ } else if len(rev) >= 5 && len(rev) <= 40 && codehost.AllHex(rev) {
+ hash = rev
+ } else {
+ return nil, nil, fmt.Errorf("unknown revision %q", rev)
+ }
+
+ out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash)
+ if err == nil {
+ hash = strings.TrimSpace(string(out))
+ goto Found
+ }
+
+ // We don't have the rev. Can we fetch it?
+ if r.local {
+ return nil, nil, fmt.Errorf("unknown revision %q", rev)
+ }
+
+ if r.canArchive {
+ // git archive with --remote requires a ref, not a hash.
+ // Proceed only if we know a ref for this hash.
+ if ref, ok := r.findRef(hash); ok {
+ out, err := codehost.Run(r.dir, "git", "archive", "--format=zip", "--remote="+r.remote, "--prefix=prefix/", ref, archiveArgs)
+ if err == nil {
+ return &codehost.RevInfo{Version: rev}, out, nil
+ }
+ if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("did not match any files")) {
+ return nil, nil, fmt.Errorf("file not found")
+ }
+ if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("Operation not supported by protocol")) {
+ r.canArchive = false
+ }
+ }
+ }
+
+ // Maybe it's a prefix of a ref we know.
+ // Iterating through all the refs is faster than doing unnecessary fetches.
+ // This is not strictly correct, in that the short ref might be ambiguous
+ // in the git repo as a whole, but not ambiguous in the list of named refs,
+ // so that we will resolve it where the git server would not.
+ // But this check avoids great expense, and preferring a known ref does
+ // not seem like such a bad failure mode.
+ if len(hash) >= 5 && len(hash) < 40 {
+ var full string
+ for _, h := range r.refs {
+ if strings.HasPrefix(h, hash) {
+ if full != "" {
+ // Prefix is ambiguous even in the ref list!
+ full = ""
+ break
+ }
+ full = h
+ }
+ }
+ if full != "" {
+ hash = full
+ }
+ }
+
+ // Fetch it.
+ if len(hash) == 40 {
+ name := hash
+ if ref, ok := r.findRef(hash); ok {
+ name = ref
+ }
+ if _, err = codehost.Run(r.dir, "git", "fetch", "--depth=1", r.remote, name); err == nil {
+ goto Found
+ }
+ if !strings.Contains(err.Error(), "unadvertised object") && !strings.Contains(err.Error(), "no such remote ref") && !strings.Contains(err.Error(), "does not support shallow") {
+ return nil, nil, err
+ }
+ }
+
+ // It's a prefix, and we don't have a way to make the server resolve the prefix for us,
+ // or it's a full hash but also an unadvertised object.
+ // Download progressively more of the repo to look for it.
+
+ // Fetch the main branch (non-shallow).
+ if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), r.remote); err != nil {
+ return nil, nil, err
+ }
+ if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil {
+ hash = strings.TrimSpace(string(out))
+ goto Found
+ }
+
+ // Fetch all tags (non-shallow).
+ if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", "--tags", r.remote); err != nil {
+ return nil, nil, err
+ }
+ if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil {
+ hash = strings.TrimSpace(string(out))
+ goto Found
+ }
+
+ // Fetch all branches (non-shallow).
+ if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", r.remote, "refs/heads/*:refs/heads/*"); err != nil {
+ return nil, nil, err
+ }
+ if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil {
+ hash = strings.TrimSpace(string(out))
+ goto Found
+ }
+
+ // Fetch all refs (non-shallow).
+ if _, err := codehost.Run(r.dir, "git", "fetch", unshallow(r.dir), "-f", r.remote, "refs/*:refs/*"); err != nil {
+ return nil, nil, err
+ }
+ if out, err := codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%H", hash); err == nil {
+ hash = strings.TrimSpace(string(out))
+ goto Found
+ }
+ return nil, nil, fmt.Errorf("cannot find hash %s", hash)
+Found:
+
+ if strings.HasPrefix(hash, rev) {
+ rev = hash
+ }
+
+ out, err = codehost.Run(r.dir, "git", "log", "-n1", "--format=format:%ct", hash)
+ if err != nil {
+ return nil, nil, err
+ }
+ t, err := strconv.ParseInt(strings.TrimSpace(string(out)), 10, 64)
+ if err != nil {
+ return nil, nil, fmt.Errorf("invalid time from git log: %q", out)
+ }
+
+ info = &codehost.RevInfo{
+ Name: hash,
+ Short: codehost.ShortenSHA1(hash),
+ Time: time.Unix(t, 0).UTC(),
+ Version: rev,
+ }
+ return info, nil, nil
+}
+
+func (r *repo) Stat(rev string) (*codehost.RevInfo, error) {
+ // If the server will give us a git archive, we can pull the
+ // commit ID and the commit time out of the archive.
+ // We want an archive as small as possible (for speed),
+ // but we have to specify a pattern that matches at least one file name.
+ // The pattern here matches README, .gitignore, .gitattributes,
+ // and go.mod (and some other incidental file names);
+ // hopefully most repos will have at least one of these.
+ info, archive, err := r.statOrArchive(rev, "[Rg.][Ego][A.i][Dmt][Miao][Edgt]*")
+ if err != nil {
+ return nil, err
+ }
+ if archive != nil {
+ return zip2info(archive, info.Version)
+ }
+ return info, nil
+}
+
+func (r *repo) ReadFile(rev, file string, maxSize int64) ([]byte, error) {
+ info, archive, err := r.statOrArchive(rev, file)
+ if err != nil {
+ return nil, err
+ }
+ if archive != nil {
+ return zip2file(archive, file, maxSize)
+ }
+ out, err := codehost.Run(r.dir, "git", "cat-file", "blob", info.Name+":"+file)
+ if err != nil {
+ return nil, fmt.Errorf("file not found")
+ }
+ return out, nil
+}
+
+func (r *repo) ReadZip(rev, subdir string, maxSize int64) (zip io.ReadCloser, actualSubdir string, err error) {
+ // TODO: Use maxSize or drop it.
+ args := []string{}
+ if subdir != "" {
+ args = append(args, "--", subdir)
+ }
+ info, archive, err := r.statOrArchive(rev, args...)
+ if err != nil {
+ return nil, "", err
+ }
+ if archive == nil {
+ archive, err = codehost.Run(r.dir, "git", "archive", "--format=zip", "--prefix=prefix/", info.Name, args)
+ if err != nil {
+ if bytes.Contains(err.(*codehost.RunError).Stderr, []byte("did not match any files")) {
+ return nil, "", fmt.Errorf("file not found")
+ }
+ return nil, "", err
+ }
+ }
+
+ return ioutil.NopCloser(bytes.NewReader(archive)), "", nil
+}
+
+func zip2info(archive []byte, rev string) (*codehost.RevInfo, error) {
+ r, err := zip.NewReader(bytes.NewReader(archive), int64(len(archive)))
+ if err != nil {
+ return nil, err
+ }
+ if r.Comment == "" {
+ return nil, fmt.Errorf("missing commit ID in git zip comment")
+ }
+ hash := r.Comment
+ if len(hash) != 40 || !codehost.AllHex(hash) {
+ return nil, fmt.Errorf("invalid commit ID in git zip comment")
+ }
+ if len(r.File) == 0 {
+ return nil, fmt.Errorf("git zip has no files")
+ }
+ info := &codehost.RevInfo{
+ Name: hash,
+ Short: codehost.ShortenSHA1(hash),
+ Time: r.File[0].Modified.UTC(),
+ Version: rev,
+ }
+ return info, nil
+}
+
+func zip2file(archive []byte, file string, maxSize int64) ([]byte, error) {
+ r, err := zip.NewReader(bytes.NewReader(archive), int64(len(archive)))
+ if err != nil {
+ return nil, err
+ }
+ for _, f := range r.File {
+ if f.Name != "prefix/"+file {
+ continue
+ }
+ rc, err := f.Open()
+ if err != nil {
+ return nil, err
+ }
+ defer rc.Close()
+ l := &io.LimitedReader{R: rc, N: maxSize + 1}
+ data, err := ioutil.ReadAll(l)
+ if err != nil {
+ return nil, err
+ }
+ if l.N <= 0 {
+ return nil, fmt.Errorf("file %s too large", file)
+ }
+ return data, nil
+ }
+ return nil, fmt.Errorf("incomplete git zip archive: cannot find %s", file)
+}
diff --git a/src/cmd/go/internal/modfetch/gitrepo/fetch_test.go b/src/cmd/go/internal/modfetch/gitrepo/fetch_test.go
new file mode 100644
index 0000000000..ca932808e8
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/gitrepo/fetch_test.go
@@ -0,0 +1,500 @@
+// Copyright 2018 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 gitrepo
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "internal/testenv"
+ "io/ioutil"
+ "log"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+ "time"
+
+ "cmd/go/internal/modfetch/codehost"
+)
+
+func TestMain(m *testing.M) {
+ os.Exit(testMain(m))
+}
+
+const gitrepo1 = "https://vcs-test.golang.org/git/gitrepo1"
+
+// localGitRepo is like gitrepo1 but allows archive access.
+var localGitRepo string
+
+func testMain(m *testing.M) int {
+ if _, err := exec.LookPath("git"); err != nil {
+ fmt.Fprintln(os.Stderr, "skipping because git binary not found")
+ fmt.Println("PASS")
+ return 0
+ }
+
+ dir, err := ioutil.TempDir("", "gitrepo-test-")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ codehost.WorkRoot = dir
+
+ if testenv.HasExternalNetwork() && testenv.HasExec() {
+ // Clone gitrepo1 into a local directory.
+ // If we use a file:// URL to access the local directory,
+ // then git starts up all the usual protocol machinery,
+ // which will let us test remote git archive invocations.
+ localGitRepo = filepath.Join(dir, "gitrepo2")
+ if _, err := codehost.Run("", "git", "clone", "--mirror", gitrepo1, localGitRepo); err != nil {
+ log.Fatal(err)
+ }
+ if _, err := codehost.Run(localGitRepo, "git", "config", "daemon.uploadarch", "true"); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ return m.Run()
+}
+
+func testRepo(remote string) (codehost.Repo, error) {
+ if remote == "localGitRepo" {
+ remote = "file://" + filepath.ToSlash(localGitRepo)
+ }
+ // Re ?root: nothing should care about the second argument,
+ // so use a string that will be distinctive if it does show up.
+ return LocalRepo(remote, "?root")
+}
+
+var tagsTests = []struct {
+ repo string
+ prefix string
+ tags []string
+}{
+ {gitrepo1, "xxx", []string{}},
+ {gitrepo1, "", []string{"v1.2.3", "v1.2.4-annotated", "v2.0.1", "v2.0.2", "v2.3"}},
+ {gitrepo1, "v", []string{"v1.2.3", "v1.2.4-annotated", "v2.0.1", "v2.0.2", "v2.3"}},
+ {gitrepo1, "v1", []string{"v1.2.3", "v1.2.4-annotated"}},
+ {gitrepo1, "2", []string{}},
+}
+
+func TestTags(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range tagsTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tags, err := r.Tags(tt.prefix)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !reflect.DeepEqual(tags, tt.tags) {
+ t.Errorf("Tags: incorrect tags\nhave %v\nwant %v", tags, tt.tags)
+ }
+ }
+ t.Run(tt.repo+"/"+tt.prefix, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(tt.repo+"/"+tt.prefix, f)
+ }
+ }
+}
+
+var latestTests = []struct {
+ repo string
+ info *codehost.RevInfo
+}{
+ {
+ gitrepo1,
+ &codehost.RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ },
+ },
+}
+
+func TestLatest(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range latestTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info, err := r.Latest()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if *info != *tt.info {
+ t.Errorf("Latest: incorrect info\nhave %+v\nwant %+v", *info, *tt.info)
+ }
+ }
+ t.Run(tt.repo, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(tt.repo, f)
+ }
+ }
+}
+
+var readFileTests = []struct {
+ repo string
+ rev string
+ file string
+ err string
+ data string
+}{
+ {
+ repo: gitrepo1,
+ rev: "HEAD",
+ file: "README",
+ data: "",
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2",
+ file: "another.txt",
+ data: "another\n",
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4",
+ file: "another.txt",
+ err: "file not found",
+ },
+}
+
+func TestReadFile(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range readFileTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ data, err := r.ReadFile(tt.rev, tt.file, 100)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("ReadFile: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("ReadFile: wrong error %q, want %q", err, tt.err)
+ }
+ if len(data) != 0 {
+ t.Errorf("ReadFile: non-empty data %q with error %v", data, err)
+ }
+ return
+ }
+ if tt.err != "" {
+ t.Fatalf("ReadFile: no error, wanted %v", tt.err)
+ }
+ if string(data) != tt.data {
+ t.Errorf("ReadFile: incorrect data\nhave %q\nwant %q", data, tt.data)
+ }
+ }
+ t.Run(tt.repo+"/"+tt.rev+"/"+tt.file, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(tt.repo+"/"+tt.rev+"/"+tt.file, f)
+ }
+ }
+}
+
+var readZipTests = []struct {
+ repo string
+ rev string
+ subdir string
+ actualSubdir string
+ err string
+ files map[string]uint64
+}{
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/README": 0,
+ "prefix/v2": 3,
+ "prefix/another.txt": 8,
+ "prefix/foo.txt": 13,
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ "prefix/README": 0,
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "v3/sub/dir",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v3",
+ subdir: "v3/sub",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/v3/": 0,
+ "prefix/v3/sub/": 0,
+ "prefix/v3/sub/dir/": 0,
+ "prefix/v3/sub/dir/file.txt": 16,
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "aaaaaaaaab",
+ subdir: "",
+ err: "cannot find hash",
+ },
+ {
+ repo: "https://github.com/rsc/vgotest1",
+ rev: "submod/v1.0.4",
+ subdir: "submod",
+ files: map[string]uint64{
+ "prefix/": 0,
+ "prefix/submod/": 0,
+ "prefix/submod/go.mod": 53,
+ "prefix/submod/pkg/": 0,
+ "prefix/submod/pkg/p.go": 31,
+ },
+ },
+}
+
+type zipFile struct {
+ name string
+ size int64
+}
+
+func TestReadZip(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range readZipTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rc, actualSubdir, err := r.ReadZip(tt.rev, tt.subdir, 100000)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("ReadZip: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("ReadZip: wrong error %q, want %q", err, tt.err)
+ }
+ if rc != nil {
+ t.Errorf("ReadZip: non-nil io.ReadCloser with error %v", err)
+ }
+ return
+ }
+ defer rc.Close()
+ if tt.err != "" {
+ t.Fatalf("ReadZip: no error, wanted %v", tt.err)
+ }
+ if actualSubdir != tt.actualSubdir {
+ t.Fatalf("ReadZip: actualSubdir = %q, want %q", actualSubdir, tt.actualSubdir)
+ }
+ zipdata, err := ioutil.ReadAll(rc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ z, err := zip.NewReader(bytes.NewReader(zipdata), int64(len(zipdata)))
+ if err != nil {
+ t.Fatalf("ReadZip: cannot read zip file: %v", err)
+ }
+ have := make(map[string]bool)
+ for _, f := range z.File {
+ size, ok := tt.files[f.Name]
+ if !ok {
+ t.Errorf("ReadZip: unexpected file %s", f.Name)
+ continue
+ }
+ have[f.Name] = true
+ if f.UncompressedSize64 != size {
+ t.Errorf("ReadZip: file %s has unexpected size %d != %d", f.Name, f.UncompressedSize64, size)
+ }
+ }
+ for name := range tt.files {
+ if !have[name] {
+ t.Errorf("ReadZip: missing file %s", name)
+ }
+ }
+ }
+ t.Run(tt.repo+"/"+tt.rev+"/"+tt.subdir, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(tt.repo+"/"+tt.rev+"/"+tt.subdir, f)
+ }
+ }
+}
+
+var statTests = []struct {
+ repo string
+ rev string
+ err string
+ info *codehost.RevInfo
+}{
+ {
+ repo: gitrepo1,
+ rev: "HEAD",
+ info: &codehost.RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2", // branch
+ info: &codehost.RevInfo{
+ Name: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
+ Short: "9d02800338b8",
+ Version: "9d02800338b8a55be062c838d1f02e0c5780b9eb",
+ Time: time.Date(2018, 4, 17, 20, 00, 32, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3.4", // badly-named branch (semver should be a tag)
+ info: &codehost.RevInfo{
+ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Short: "76a00fb249b7",
+ Version: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v2.3", // badly-named tag (we only respect full semver v2.3.0)
+ info: &codehost.RevInfo{
+ Name: "76a00fb249b7f93091bc2c89a789dab1fc1bc26f",
+ Short: "76a00fb249b7",
+ Version: "v2.3",
+ Time: time.Date(2018, 4, 17, 19, 45, 48, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v1.2.3", // tag
+ info: &codehost.RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "v1.2.3",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "ede458df", // hash prefix in refs
+ info: &codehost.RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "97f6aa59", // hash prefix not in refs
+ info: &codehost.RevInfo{
+ Name: "97f6aa59c81c623494825b43d39e445566e429a4",
+ Short: "97f6aa59c81c",
+ Version: "97f6aa59c81c623494825b43d39e445566e429a4",
+ Time: time.Date(2018, 4, 17, 20, 0, 19, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "v1.2.4-annotated", // annotated tag uses unwrapped commit hash
+ info: &codehost.RevInfo{
+ Name: "ede458df7cd0fdca520df19a33158086a8a68e81",
+ Short: "ede458df7cd0",
+ Version: "v1.2.4-annotated",
+ Time: time.Date(2018, 4, 17, 19, 43, 22, 0, time.UTC),
+ },
+ },
+ {
+ repo: gitrepo1,
+ rev: "aaaaaaaaab",
+ err: "cannot find hash",
+ },
+}
+
+func TestStat(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+ testenv.MustHaveExec(t)
+
+ for _, tt := range statTests {
+ f := func(t *testing.T) {
+ r, err := testRepo(tt.repo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ info, err := r.Stat(tt.rev)
+ if err != nil {
+ if tt.err == "" {
+ t.Fatalf("Stat: unexpected error %v", err)
+ }
+ if !strings.Contains(err.Error(), tt.err) {
+ t.Fatalf("Stat: wrong error %q, want %q", err, tt.err)
+ }
+ if info != nil {
+ t.Errorf("Stat: non-nil info with error %q", err)
+ }
+ return
+ }
+ if *info != *tt.info {
+ t.Errorf("Stat: incorrect info\nhave %+v\nwant %+v", *info, *tt.info)
+ }
+ }
+ t.Run(filepath.Base(tt.repo)+"/"+tt.rev, f)
+ if tt.repo == gitrepo1 {
+ tt.repo = "localGitRepo"
+ t.Run(filepath.Base(tt.repo)+"/"+tt.rev, f)
+ }
+ }
+}
diff --git a/src/cmd/go/internal/modfetch/googlesource/fetch.go b/src/cmd/go/internal/modfetch/googlesource/fetch.go
new file mode 100644
index 0000000000..8317ac3e29
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/googlesource/fetch.go
@@ -0,0 +1,25 @@
+// Copyright 2018 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 googlesource
+
+import (
+ "fmt"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/gitrepo"
+)
+
+func Lookup(path string) (codehost.Repo, error) {
+ i := strings.Index(path, "/")
+ if i+1 == len(path) || !strings.HasSuffix(path[:i+1], ".googlesource.com/") {
+ return nil, fmt.Errorf("not *.googlesource.com/*")
+ }
+ j := strings.Index(path[i+1:], "/")
+ if j >= 0 {
+ path = path[:i+1+j]
+ }
+ return gitrepo.Repo("https://"+path, path)
+}
diff --git a/src/cmd/go/internal/modfetch/gopkgin.go b/src/cmd/go/internal/modfetch/gopkgin.go
new file mode 100644
index 0000000000..d49b60b3f0
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/gopkgin.go
@@ -0,0 +1,22 @@
+// Copyright 2018 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.
+
+// TODO: Figure out what gopkg.in should do.
+
+package modfetch
+
+import (
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/gitrepo"
+ "cmd/go/internal/modfile"
+ "fmt"
+)
+
+func gopkginLookup(path string) (codehost.Repo, error) {
+ root, _, _, _, ok := modfile.ParseGopkgIn(path)
+ if !ok {
+ return nil, fmt.Errorf("invalid gopkg.in/ path: %q", path)
+ }
+ return gitrepo.Repo("https://"+root, root)
+}
diff --git a/src/cmd/go/internal/modfetch/noweb.go b/src/cmd/go/internal/modfetch/noweb.go
new file mode 100644
index 0000000000..9d713dcc66
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/noweb.go
@@ -0,0 +1,24 @@
+// Copyright 2018 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 cmd_go_bootstrap
+
+package modfetch
+
+import (
+ "fmt"
+ "io"
+)
+
+func webGetGoGet(url string, body *io.ReadCloser) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
+
+func webGetBytes(url string, body *[]byte) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
+
+func webGetBody(url string, body *io.ReadCloser) error {
+ return fmt.Errorf("no network in go_bootstrap")
+}
diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go
new file mode 100644
index 0000000000..419323bb3b
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/proxy.go
@@ -0,0 +1,164 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "encoding/json"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/url"
+ "os"
+ "strings"
+ "time"
+
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/semver"
+)
+
+var proxyURL = os.Getenv("GOPROXY")
+
+func lookupProxy(path string) (Repo, error) {
+ u, err := url.Parse(proxyURL)
+ if err != nil || u.Scheme != "http" && u.Scheme != "https" && u.Scheme != "file" {
+ // Don't echo $GOPROXY back in case it has user:password in it (sigh).
+ return nil, fmt.Errorf("invalid $GOPROXY setting")
+ }
+ return newProxyRepo(u.String(), path), nil
+}
+
+type proxyRepo struct {
+ url string
+ path string
+}
+
+func newProxyRepo(baseURL, path string) Repo {
+ return &proxyRepo{strings.TrimSuffix(baseURL, "/") + "/" + pathEscape(path), path}
+}
+
+func (p *proxyRepo) ModulePath() string {
+ return p.path
+}
+
+func (p *proxyRepo) Versions(prefix string) ([]string, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/list", &data)
+ if err != nil {
+ return nil, err
+ }
+ var list []string
+ for _, line := range strings.Split(string(data), "\n") {
+ f := strings.Fields(line)
+ if len(f) >= 1 && semver.IsValid(f[0]) && strings.HasPrefix(f[0], prefix) {
+ list = append(list, f[0])
+ }
+ }
+ return list, nil
+}
+
+func (p *proxyRepo) latest() (*RevInfo, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/list", &data)
+ if err != nil {
+ return nil, err
+ }
+ var best time.Time
+ var bestVersion string
+ for _, line := range strings.Split(string(data), "\n") {
+ f := strings.Fields(line)
+ if len(f) >= 2 && semver.IsValid(f[0]) {
+ ft, err := time.Parse(time.RFC3339, f[1])
+ if err == nil && best.Before(ft) {
+ best = ft
+ bestVersion = f[0]
+ }
+ }
+ }
+ if bestVersion == "" {
+ return nil, fmt.Errorf("no commits")
+ }
+ info := &RevInfo{
+ Version: bestVersion,
+ Name: bestVersion,
+ Short: bestVersion,
+ Time: best,
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) Stat(rev string) (*RevInfo, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/"+pathEscape(rev)+".info", &data)
+ if err != nil {
+ return nil, err
+ }
+ info := new(RevInfo)
+ if err := json.Unmarshal(data, info); err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) Latest() (*RevInfo, error) {
+ var data []byte
+ u := p.url + "/@latest"
+ err := webGetBytes(u, &data)
+ if err != nil {
+ // TODO return err if not 404
+ return p.latest()
+ }
+ info := new(RevInfo)
+ if err := json.Unmarshal(data, info); err != nil {
+ return nil, err
+ }
+ return info, nil
+}
+
+func (p *proxyRepo) GoMod(version string) ([]byte, error) {
+ var data []byte
+ err := webGetBytes(p.url+"/@v/"+pathEscape(version)+".mod", &data)
+ if err != nil {
+ return nil, err
+ }
+ return data, nil
+}
+
+func (p *proxyRepo) Zip(version string, tmpdir string) (tmpfile string, err error) {
+ var body io.ReadCloser
+ err = webGetBody(p.url+"/@v/"+pathEscape(version)+".zip", &body)
+ if err != nil {
+ return "", err
+ }
+ defer body.Close()
+
+ // Spool to local file.
+ f, err := ioutil.TempFile(tmpdir, "vgo-proxy-download-")
+ if err != nil {
+ return "", err
+ }
+ defer f.Close()
+ maxSize := int64(codehost.MaxZipFile)
+ lr := &io.LimitedReader{R: body, N: maxSize + 1}
+ if _, err := io.Copy(f, lr); err != nil {
+ os.Remove(f.Name())
+ return "", err
+ }
+ if lr.N <= 0 {
+ os.Remove(f.Name())
+ return "", fmt.Errorf("downloaded zip file too large")
+ }
+ if err := f.Close(); err != nil {
+ os.Remove(f.Name())
+ return "", err
+ }
+ return f.Name(), nil
+}
+
+// pathEscape escapes s so it can be used in a path.
+// That is, it escapes things like ? and # (which really shouldn't appear anyway).
+// It does not escape / to %2F: our REST API is designed so that / can be left as is.
+func pathEscape(s string) string {
+ return strings.Replace(url.PathEscape(s), "%2F", "/", -1)
+}
diff --git a/src/cmd/go/internal/modfetch/query.go b/src/cmd/go/internal/modfetch/query.go
new file mode 100644
index 0000000000..5e9d86c411
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/query.go
@@ -0,0 +1,84 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+ "fmt"
+ "strings"
+)
+
+// Query looks up a revision of a given module given a version query string.
+// The module must be a complete module path.
+// The version must take one of the following forms:
+//
+// - the literal string "latest", denoting the latest available tagged version
+// - v1.2.3, a semantic version string
+// - v1 or v1.2, an abbreviated semantic version string completed by adding zeroes (v1.0.0 or v1.2.0);
+// - >v1.2.3, denoting the earliest available version after v1.2.3
+// - <v1.2.3, denoting the latest available version before v1.2.3
+// - an RFC 3339 time stamp, denoting the latest available version at that time
+// - a Unix time expressed as seconds since 1970, denoting the latest available version at that time
+// - a repository commit identifier, denoting that version
+//
+// The time stamps can be followed by an optional @branch suffix to limit the
+// result to revisions on a particular branch name.
+//
+func Query(path, vers string, allowed func(module.Version) bool) (*RevInfo, error) {
+ repo, err := Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+
+ if strings.HasPrefix(vers, "v") && semver.IsValid(vers) {
+ // TODO: This turns query for "v2" into Stat "v2.0.0",
+ // but probably it should allow checking for a branch named "v2".
+ vers = semver.Canonical(vers)
+ if allowed != nil && !allowed(module.Version{Path: path, Version: vers}) {
+ return nil, fmt.Errorf("%s@%s excluded", path, vers)
+ }
+ return repo.Stat(vers)
+ }
+ if strings.HasPrefix(vers, ">") || strings.HasPrefix(vers, "<") || vers == "latest" {
+ var op string
+ if vers != "latest" {
+ if !semver.IsValid(vers[1:]) {
+ return nil, fmt.Errorf("invalid semantic version in range %s", vers)
+ }
+ op, vers = vers[:1], vers[1:]
+ }
+ versions, err := repo.Versions("")
+ if err != nil {
+ return nil, err
+ }
+ if len(versions) == 0 && vers == "latest" {
+ return repo.Latest()
+ }
+ if vers == "latest" {
+ for i := len(versions) - 1; i >= 0; i-- {
+ if allowed == nil || allowed(module.Version{Path: path, Version: versions[i]}) {
+ return repo.Stat(versions[i])
+ }
+ }
+ } else if op == "<" {
+ for i := len(versions) - 1; i >= 0; i-- {
+ if semver.Compare(versions[i], vers) < 0 && (allowed == nil || allowed(module.Version{Path: path, Version: versions[i]})) {
+ return repo.Stat(versions[i])
+ }
+ }
+ } else {
+ for i := 0; i < len(versions); i++ {
+ if semver.Compare(versions[i], vers) > 0 && (allowed == nil || allowed(module.Version{Path: path, Version: versions[i]})) {
+ return repo.Stat(versions[i])
+ }
+ }
+ }
+ return nil, fmt.Errorf("no matching versions for %s%s", op, vers)
+ }
+ // TODO: Time queries, maybe.
+
+ return repo.Stat(vers)
+}
diff --git a/src/cmd/go/internal/modfetch/repo.go b/src/cmd/go/internal/modfetch/repo.go
new file mode 100644
index 0000000000..6e21a41777
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/repo.go
@@ -0,0 +1,137 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "errors"
+ pathpkg "path"
+ "sort"
+ "strings"
+ "time"
+
+ "cmd/go/internal/modfetch/bitbucket"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfetch/github"
+ "cmd/go/internal/modfetch/googlesource"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+// A Repo represents a repository storing all versions of a single module.
+type Repo interface {
+ // ModulePath returns the module path.
+ ModulePath() string
+
+ // Versions lists all known versions with the given prefix.
+ // Pseudo-versions are not included.
+ // Versions should be returned sorted in semver order
+ // (implementations can use SortVersions).
+ Versions(prefix string) (tags []string, err error)
+
+ // Stat returns information about the revision rev.
+ // A revision can be any identifier known to the underlying service:
+ // commit hash, branch, tag, and so on.
+ Stat(rev string) (*RevInfo, error)
+
+ // Latest returns the latest revision on the default branch,
+ // whatever that means in the underlying source code repository.
+ // It is only used when there are no tagged versions.
+ Latest() (*RevInfo, error)
+
+ // GoMod returns the go.mod file for the given version.
+ GoMod(version string) (data []byte, err error)
+
+ // Zip downloads a zip file for the given version
+ // to a new file in a given temporary directory.
+ // It returns the name of the new file.
+ // The caller should remove the file when finished with it.
+ Zip(version, tmpdir string) (tmpfile string, err error)
+}
+
+// A Rev describes a single revision in a module repository.
+type RevInfo struct {
+ Version string // version string
+ Name string // complete ID in underlying repository
+ Short string // shortened ID, for use in pseudo-version
+ Time time.Time // commit time
+}
+
+// Lookup returns the module with the given module path.
+func Lookup(path string) (Repo, error) {
+ if proxyURL != "" {
+ return lookupProxy(path)
+ }
+ if code, err := lookupCodeHost(path, false); err != errNotHosted {
+ if err != nil {
+ return nil, err
+ }
+ return newCodeRepo(code, path)
+ }
+ return lookupCustomDomain(path)
+}
+
+func Import(path string, allowed func(module.Version) bool) (Repo, *RevInfo, error) {
+ try := func(path string) (Repo, *RevInfo, error) {
+ r, err := Lookup(path)
+ if err != nil {
+ return nil, nil, err
+ }
+ info, err := Query(path, "latest", allowed)
+ if err != nil {
+ return nil, nil, err
+ }
+ _, err = r.GoMod(info.Version)
+ if err != nil {
+ return nil, nil, err
+ }
+ return r, info, nil
+ }
+
+ var firstErr error
+ for {
+ r, info, err := try(path)
+ if err == nil {
+ return r, info, nil
+ }
+ if firstErr == nil {
+ firstErr = err
+ }
+ p := pathpkg.Dir(path)
+ if p == "." {
+ break
+ }
+ path = p
+ }
+ return nil, nil, firstErr
+}
+
+var errNotHosted = errors.New("not hosted")
+
+var isTest bool
+
+func lookupCodeHost(path string, customDomain bool) (codehost.Repo, error) {
+ switch {
+ case strings.HasPrefix(path, "github.com/"):
+ return github.Lookup(path)
+ case strings.HasPrefix(path, "bitbucket.org/"):
+ return bitbucket.Lookup(path)
+ case customDomain && strings.HasSuffix(path[:strings.Index(path, "/")+1], ".googlesource.com/") ||
+ isTest && strings.HasPrefix(path, "go.googlesource.com/scratch"):
+ return googlesource.Lookup(path)
+ case strings.HasPrefix(path, "gopkg.in/"):
+ return gopkginLookup(path)
+ }
+ return nil, errNotHosted
+}
+
+func SortVersions(list []string) {
+ sort.Slice(list, func(i, j int) bool {
+ cmp := semver.Compare(list[i], list[j])
+ if cmp != 0 {
+ return cmp < 0
+ }
+ return list[i] < list[j]
+ })
+}
diff --git a/src/cmd/go/internal/modfetch/unzip.go b/src/cmd/go/internal/modfetch/unzip.go
new file mode 100644
index 0000000000..9d9e29889e
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/unzip.go
@@ -0,0 +1,100 @@
+// Copyright 2018 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 modfetch
+
+import (
+ "archive/zip"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/modfetch/codehost"
+)
+
+func Unzip(dir, zipfile, prefix string, maxSize int64) error {
+ if maxSize == 0 {
+ maxSize = codehost.MaxZipFile
+ }
+
+ // Directory can exist, but must be empty.
+ // except maybe
+ files, _ := ioutil.ReadDir(dir)
+ if len(files) > 0 {
+ return fmt.Errorf("target directory %v exists and is not empty", dir)
+ }
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return err
+ }
+
+ f, err := os.Open(zipfile)
+ if err != nil {
+ return err
+ }
+ defer f.Close()
+ info, err := f.Stat()
+ if err != nil {
+ return err
+ }
+
+ z, err := zip.NewReader(f, info.Size())
+ if err != nil {
+ return fmt.Errorf("unzip %v: %s", zipfile, err)
+ }
+
+ // Check total size.
+ var size int64
+ for _, zf := range z.File {
+ if !strings.HasPrefix(zf.Name, prefix) {
+ return fmt.Errorf("unzip %v: unexpected file name %s", zipfile, zf.Name)
+ }
+ if strings.HasSuffix(zf.Name, "/") {
+ continue
+ }
+ s := int64(zf.UncompressedSize64)
+ if s < 0 || maxSize-size < s {
+ return fmt.Errorf("unzip %v: content too large", zipfile)
+ }
+ size += s
+ }
+
+ // Unzip, enforcing sizes checked earlier.
+ for _, zf := range z.File {
+ if strings.HasSuffix(zf.Name, "/") {
+ continue
+ }
+ dst := filepath.Join(dir, zf.Name[len(prefix):])
+ if err := os.MkdirAll(filepath.Dir(dst), 0777); err != nil {
+ return err
+ }
+ w, err := os.OpenFile(dst, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0444)
+ if err != nil {
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ r, err := zf.Open()
+ if err != nil {
+ r.Close()
+ w.Close()
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ lr := &io.LimitedReader{R: r, N: int64(zf.UncompressedSize64) + 1}
+ _, err = io.Copy(w, lr)
+ r.Close()
+ if err != nil {
+ w.Close()
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ if err := w.Close(); err != nil {
+ return fmt.Errorf("unzip %v: %v", zipfile, err)
+ }
+ if lr.N <= 0 {
+ return fmt.Errorf("unzip %v: content too large", zipfile)
+ }
+ }
+
+ return nil
+}
diff --git a/src/cmd/go/internal/modfetch/web.go b/src/cmd/go/internal/modfetch/web.go
new file mode 100644
index 0000000000..b327bf293d
--- /dev/null
+++ b/src/cmd/go/internal/modfetch/web.go
@@ -0,0 +1,31 @@
+// Copyright 2018 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 !cmd_go_bootstrap
+
+package modfetch
+
+import (
+ "io"
+
+ web "cmd/go/internal/web2"
+)
+
+// webGetGoGet fetches a go-get=1 URL and returns the body in *body.
+// It allows non-200 responses, as usual for these URLs.
+func webGetGoGet(url string, body *io.ReadCloser) error {
+ return web.Get(url, web.Non200OK(), web.Body(body))
+}
+
+// webGetBytes returns the body returned by an HTTP GET, as a []byte.
+// It insists on a 200 response.
+func webGetBytes(url string, body *[]byte) error {
+ return web.Get(url, web.ReadAllBody(body))
+}
+
+// webGetBody returns the body returned by an HTTP GET, as a io.ReadCloser.
+// It insists on a 200 response.
+func webGetBody(url string, body *io.ReadCloser) error {
+ return web.Get(url, web.Body(body))
+}
diff --git a/src/cmd/go/internal/modfile/gopkgin.go b/src/cmd/go/internal/modfile/gopkgin.go
new file mode 100644
index 0000000000..c94b3848a0
--- /dev/null
+++ b/src/cmd/go/internal/modfile/gopkgin.go
@@ -0,0 +1,47 @@
+// Copyright 2018 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.
+
+// TODO: Figure out what gopkg.in should do.
+
+package modfile
+
+import "strings"
+
+// ParseGopkgIn splits gopkg.in import paths into their constituent parts
+func ParseGopkgIn(path string) (root, repo, major, subdir string, ok bool) {
+ if !strings.HasPrefix(path, "gopkg.in/") {
+ return
+ }
+ f := strings.Split(path, "/")
+ if len(f) >= 2 {
+ if elem, v, ok := dotV(f[1]); ok {
+ root = strings.Join(f[:2], "/")
+ repo = "github.com/go-" + elem + "/" + elem
+ major = v
+ subdir = strings.Join(f[2:], "/")
+ return root, repo, major, subdir, true
+ }
+ }
+ if len(f) >= 3 {
+ if elem, v, ok := dotV(f[2]); ok {
+ root = strings.Join(f[:3], "/")
+ repo = "github.com/" + f[1] + "/" + elem
+ major = v
+ subdir = strings.Join(f[3:], "/")
+ return root, repo, major, subdir, true
+ }
+ }
+ return
+}
+
+func dotV(name string) (elem, v string, ok bool) {
+ i := len(name) - 1
+ for i >= 0 && '0' <= name[i] && name[i] <= '9' {
+ i--
+ }
+ if i <= 2 || i+1 >= len(name) || name[i-1] != '.' || name[i] != 'v' || name[i+1] == '0' && len(name) != i+2 {
+ return "", "", false
+ }
+ return name[:i-1], name[i:], true
+}
diff --git a/src/cmd/go/internal/modfile/print.go b/src/cmd/go/internal/modfile/print.go
new file mode 100644
index 0000000000..cefc43b141
--- /dev/null
+++ b/src/cmd/go/internal/modfile/print.go
@@ -0,0 +1,164 @@
+// Copyright 2018 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.
+
+// Module file printer.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "strings"
+)
+
+func Format(f *FileSyntax) []byte {
+ pr := &printer{}
+ pr.file(f)
+ return pr.Bytes()
+}
+
+// A printer collects the state during printing of a file or expression.
+type printer struct {
+ bytes.Buffer // output buffer
+ comment []Comment // pending end-of-line comments
+ margin int // left margin (indent), a number of tabs
+}
+
+// printf prints to the buffer.
+func (p *printer) printf(format string, args ...interface{}) {
+ fmt.Fprintf(p, format, args...)
+}
+
+// indent returns the position on the current line, in bytes, 0-indexed.
+func (p *printer) indent() int {
+ b := p.Bytes()
+ n := 0
+ for n < len(b) && b[len(b)-1-n] != '\n' {
+ n++
+ }
+ return n
+}
+
+// newline ends the current line, flushing end-of-line comments.
+func (p *printer) newline() {
+ if len(p.comment) > 0 {
+ p.printf(" ")
+ for i, com := range p.comment {
+ if i > 0 {
+ p.trim()
+ p.printf("\n")
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+ }
+ p.printf("%s", strings.TrimSpace(com.Token))
+ }
+ p.comment = p.comment[:0]
+ }
+
+ p.trim()
+ p.printf("\n")
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+}
+
+// trim removes trailing spaces and tabs from the current line.
+func (p *printer) trim() {
+ // Remove trailing spaces and tabs from line we're about to end.
+ b := p.Bytes()
+ n := len(b)
+ for n > 0 && (b[n-1] == '\t' || b[n-1] == ' ') {
+ n--
+ }
+ p.Truncate(n)
+}
+
+// file formats the given file into the print buffer.
+func (p *printer) file(f *FileSyntax) {
+ for _, com := range f.Before {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+
+ for i, stmt := range f.Stmt {
+ switch x := stmt.(type) {
+ case *CommentBlock:
+ // comments already handled
+ p.expr(x)
+
+ default:
+ p.expr(x)
+ p.newline()
+ }
+
+ for _, com := range stmt.Comment().After {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+
+ if i+1 < len(f.Stmt) {
+ p.newline()
+ }
+ }
+}
+
+func (p *printer) expr(x Expr) {
+ // Emit line-comments preceding this expression.
+ if before := x.Comment().Before; len(before) > 0 {
+ // Want to print a line comment.
+ // Line comments must be at the current margin.
+ p.trim()
+ if p.indent() > 0 {
+ // There's other text on the line. Start a new line.
+ p.printf("\n")
+ }
+ // Re-indent to margin.
+ for i := 0; i < p.margin; i++ {
+ p.printf("\t")
+ }
+ for _, com := range before {
+ p.printf("%s", strings.TrimSpace(com.Token))
+ p.newline()
+ }
+ }
+
+ switch x := x.(type) {
+ default:
+ panic(fmt.Errorf("printer: unexpected type %T", x))
+
+ case *CommentBlock:
+ // done
+
+ case *LParen:
+ p.printf("(")
+ case *RParen:
+ p.printf(")")
+
+ case *Line:
+ sep := ""
+ for _, tok := range x.Token {
+ p.printf("%s%s", sep, tok)
+ sep = " "
+ }
+
+ case *LineBlock:
+ for _, tok := range x.Token {
+ p.printf("%s ", tok)
+ }
+ p.expr(&x.LParen)
+ p.margin++
+ for _, l := range x.Line {
+ p.newline()
+ p.expr(l)
+ }
+ p.margin--
+ p.newline()
+ p.expr(&x.RParen)
+ }
+
+ // Queue end-of-line comments for printing when we
+ // reach the end of the line.
+ p.comment = append(p.comment, x.Comment().Suffix...)
+}
diff --git a/src/cmd/go/internal/modfile/read.go b/src/cmd/go/internal/modfile/read.go
new file mode 100644
index 0000000000..a0c88d6ca9
--- /dev/null
+++ b/src/cmd/go/internal/modfile/read.go
@@ -0,0 +1,699 @@
+// Copyright 2018 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.
+
+// Module file parser.
+// This is a simplified copy of Google's buildifier parser.
+
+package modfile
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+)
+
+// A Position describes the position between two bytes of input.
+type Position struct {
+ Line int // line in input (starting at 1)
+ LineRune int // rune in line (starting at 1)
+ Byte int // byte in input (starting at 0)
+}
+
+// add returns the position at the end of s, assuming it starts at p.
+func (p Position) add(s string) Position {
+ p.Byte += len(s)
+ if n := strings.Count(s, "\n"); n > 0 {
+ p.Line += n
+ s = s[strings.LastIndex(s, "\n")+1:]
+ p.LineRune = 1
+ }
+ p.LineRune += utf8.RuneCountInString(s)
+ return p
+}
+
+// An Expr represents an input element.
+type Expr interface {
+ // Span returns the start and end position of the expression,
+ // excluding leading or trailing comments.
+ Span() (start, end Position)
+
+ // Comment returns the comments attached to the expression.
+ // This method would normally be named 'Comments' but that
+ // would interfere with embedding a type of the same name.
+ Comment() *Comments
+}
+
+// A Comment represents a single // comment.
+type Comment struct {
+ Start Position
+ Token string // without trailing newline
+ Suffix bool // an end of line (not whole line) comment
+}
+
+// Comments collects the comments associated with an expression.
+type Comments struct {
+ Before []Comment // whole-line comments before this expression
+ Suffix []Comment // end-of-line comments after this expression
+
+ // For top-level expressions only, After lists whole-line
+ // comments following the expression.
+ After []Comment
+}
+
+// Comment returns the receiver. This isn't useful by itself, but
+// a Comments struct is embedded into all the expression
+// implementation types, and this gives each of those a Comment
+// method to satisfy the Expr interface.
+func (c *Comments) Comment() *Comments {
+ return c
+}
+
+// A FileSyntax represents an entire go.mod file.
+type FileSyntax struct {
+ Name string // file path
+ Comments
+ Stmt []Expr
+}
+
+func (x *FileSyntax) Span() (start, end Position) {
+ if len(x.Stmt) == 0 {
+ return
+ }
+ start, _ = x.Stmt[0].Span()
+ _, end = x.Stmt[len(x.Stmt)-1].Span()
+ return start, end
+}
+
+// A CommentBlock represents a top-level block of comments separate
+// from any rule.
+type CommentBlock struct {
+ Comments
+ Start Position
+}
+
+func (x *CommentBlock) Span() (start, end Position) {
+ return x.Start, x.Start
+}
+
+// A Line is a single line of tokens.
+type Line struct {
+ Comments
+ Start Position
+ Token []string
+ End Position
+}
+
+func (x *Line) Span() (start, end Position) {
+ return x.Start, x.End
+}
+
+// A LineBlock is a factored block of lines, like
+//
+// require (
+// "x"
+// "y"
+// )
+//
+type LineBlock struct {
+ Comments
+ Start Position
+ LParen LParen
+ Token []string
+ Line []*Line
+ RParen RParen
+}
+
+func (x *LineBlock) Span() (start, end Position) {
+ return x.Start, x.RParen.Pos.add(")")
+}
+
+// An LParen represents the beginning of a parenthesized line block.
+// It is a place to store suffix comments.
+type LParen struct {
+ Comments
+ Pos Position
+}
+
+func (x *LParen) Span() (start, end Position) {
+ return x.Pos, x.Pos.add(")")
+}
+
+// An RParen represents the end of a parenthesized line block.
+// It is a place to store whole-line (before) comments.
+type RParen struct {
+ Comments
+ Pos Position
+}
+
+func (x *RParen) Span() (start, end Position) {
+ return x.Pos, x.Pos.add(")")
+}
+
+// An input represents a single input file being parsed.
+type input struct {
+ // Lexing state.
+ filename string // name of input file, for errors
+ complete []byte // entire input
+ remaining []byte // remaining input
+ token []byte // token being scanned
+ lastToken string // most recently returned token, for error messages
+ pos Position // current input position
+ comments []Comment // accumulated comments
+ endRule int // position of end of current rule
+
+ // Parser state.
+ file *FileSyntax // returned top-level syntax tree
+ parseError error // error encountered during parsing
+
+ // Comment assignment state.
+ pre []Expr // all expressions, in preorder traversal
+ post []Expr // all expressions, in postorder traversal
+}
+
+func newInput(filename string, data []byte) *input {
+ return &input{
+ filename: filename,
+ complete: data,
+ remaining: data,
+ pos: Position{Line: 1, LineRune: 1, Byte: 0},
+ }
+}
+
+// parse parses the input file.
+func parse(file string, data []byte) (f *FileSyntax, err error) {
+ in := newInput(file, data)
+ // The parser panics for both routine errors like syntax errors
+ // and for programmer bugs like array index errors.
+ // Turn both into error returns. Catching bug panics is
+ // especially important when processing many files.
+ defer func() {
+ if e := recover(); e != nil {
+ if e == in.parseError {
+ err = in.parseError
+ } else {
+ err = fmt.Errorf("%s:%d:%d: internal error: %v", in.filename, in.pos.Line, in.pos.LineRune, e)
+ }
+ }
+ }()
+
+ // Invoke the parser.
+ in.parseFile()
+ if in.parseError != nil {
+ return nil, in.parseError
+ }
+ in.file.Name = in.filename
+
+ // Assign comments to nearby syntax.
+ in.assignComments()
+
+ return in.file, nil
+}
+
+// Error is called to report an error.
+// The reason s is often "syntax error".
+// Error does not return: it panics.
+func (in *input) Error(s string) {
+ if s == "syntax error" && in.lastToken != "" {
+ s += " near " + in.lastToken
+ }
+ in.parseError = fmt.Errorf("%s:%d:%d: %v", in.filename, in.pos.Line, in.pos.LineRune, s)
+ panic(in.parseError)
+}
+
+// eof reports whether the input has reached end of file.
+func (in *input) eof() bool {
+ return len(in.remaining) == 0
+}
+
+// peekRune returns the next rune in the input without consuming it.
+func (in *input) peekRune() int {
+ if len(in.remaining) == 0 {
+ return 0
+ }
+ r, _ := utf8.DecodeRune(in.remaining)
+ return int(r)
+}
+
+// peekPrefix reports whether the remaining input begins with the given prefix.
+func (in *input) peekPrefix(prefix string) bool {
+ // This is like bytes.HasPrefix(in.remaining, []byte(prefix))
+ // but without the allocation of the []byte copy of prefix.
+ for i := 0; i < len(prefix); i++ {
+ if i >= len(in.remaining) || in.remaining[i] != prefix[i] {
+ return false
+ }
+ }
+ return true
+}
+
+// readRune consumes and returns the next rune in the input.
+func (in *input) readRune() int {
+ if len(in.remaining) == 0 {
+ in.Error("internal lexer error: readRune at EOF")
+ }
+ r, size := utf8.DecodeRune(in.remaining)
+ in.remaining = in.remaining[size:]
+ if r == '\n' {
+ in.pos.Line++
+ in.pos.LineRune = 1
+ } else {
+ in.pos.LineRune++
+ }
+ in.pos.Byte += size
+ return int(r)
+}
+
+type symType struct {
+ pos Position
+ endPos Position
+ text string
+}
+
+// startToken marks the beginning of the next input token.
+// It must be followed by a call to endToken, once the token has
+// been consumed using readRune.
+func (in *input) startToken(sym *symType) {
+ in.token = in.remaining
+ sym.text = ""
+ sym.pos = in.pos
+}
+
+// endToken marks the end of an input token.
+// It records the actual token string in sym.text if the caller
+// has not done that already.
+func (in *input) endToken(sym *symType) {
+ if sym.text == "" {
+ tok := string(in.token[:len(in.token)-len(in.remaining)])
+ sym.text = tok
+ in.lastToken = sym.text
+ }
+ sym.endPos = in.pos
+}
+
+// lex is called from the parser to obtain the next input token.
+// It returns the token value (either a rune like '+' or a symbolic token _FOR)
+// and sets val to the data associated with the token.
+// For all our input tokens, the associated data is
+// val.Pos (the position where the token begins)
+// and val.Token (the input string corresponding to the token).
+func (in *input) lex(sym *symType) int {
+ // Skip past spaces, stopping at non-space or EOF.
+ countNL := 0 // number of newlines we've skipped past
+ for !in.eof() {
+ // Skip over spaces. Count newlines so we can give the parser
+ // information about where top-level blank lines are,
+ // for top-level comment assignment.
+ c := in.peekRune()
+ if c == ' ' || c == '\t' || c == '\r' {
+ in.readRune()
+ continue
+ }
+
+ // Comment runs to end of line.
+ if in.peekPrefix("//") {
+ in.startToken(sym)
+
+ // Is this comment the only thing on its line?
+ // Find the last \n before this // and see if it's all
+ // spaces from there to here.
+ i := bytes.LastIndex(in.complete[:in.pos.Byte], []byte("\n"))
+ suffix := len(bytes.TrimSpace(in.complete[i+1:in.pos.Byte])) > 0
+ in.readRune()
+ in.readRune()
+
+ // Consume comment.
+ for len(in.remaining) > 0 && in.readRune() != '\n' {
+ }
+ in.endToken(sym)
+
+ sym.text = strings.TrimRight(sym.text, "\n")
+ in.lastToken = "comment"
+
+ // If we are at top level (not in a statement), hand the comment to
+ // the parser as a _COMMENT token. The grammar is written
+ // to handle top-level comments itself.
+ if !suffix {
+ // Not in a statement. Tell parser about top-level comment.
+ return _COMMENT
+ }
+
+ // Otherwise, save comment for later attachment to syntax tree.
+ if countNL > 1 {
+ in.comments = append(in.comments, Comment{sym.pos, "", false})
+ }
+ in.comments = append(in.comments, Comment{sym.pos, sym.text, suffix})
+ countNL = 1
+ return _EOL
+ }
+
+ if in.peekPrefix("/*") {
+ in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
+ }
+
+ // Found non-space non-comment.
+ break
+ }
+
+ // Found the beginning of the next token.
+ in.startToken(sym)
+ defer in.endToken(sym)
+
+ // End of file.
+ if in.eof() {
+ in.lastToken = "EOF"
+ return _EOF
+ }
+
+ // Punctuation tokens.
+ switch c := in.peekRune(); c {
+ case '\n':
+ in.readRune()
+ return c
+
+ case '(':
+ in.readRune()
+ return c
+
+ case ')':
+ in.readRune()
+ return c
+
+ case '"', '`': // quoted string
+ quote := c
+ in.readRune()
+ for {
+ if in.eof() {
+ in.pos = sym.pos
+ in.Error("unexpected EOF in string")
+ }
+ if in.peekRune() == '\n' {
+ in.Error("unexpected newline in string")
+ }
+ c := in.readRune()
+ if c == quote {
+ break
+ }
+ if c == '\\' && quote != '`' {
+ if in.eof() {
+ in.pos = sym.pos
+ in.Error("unexpected EOF in string")
+ }
+ in.readRune()
+ }
+ }
+ in.endToken(sym)
+ return _STRING
+ }
+
+ // Checked all punctuation. Must be identifier token.
+ if c := in.peekRune(); !isIdent(c) {
+ in.Error(fmt.Sprintf("unexpected input character %#q", c))
+ }
+
+ // Scan over identifier.
+ for isIdent(in.peekRune()) {
+ if in.peekPrefix("//") {
+ break
+ }
+ if in.peekPrefix("/*") {
+ in.Error(fmt.Sprintf("mod files must use // comments (not /* */ comments)"))
+ }
+ in.readRune()
+ }
+ return _IDENT
+}
+
+// isIdent reports whether c is an identifier rune.
+// We treat nearly all runes as identifier runes.
+func isIdent(c int) bool {
+ return c != 0 && !unicode.IsSpace(rune(c))
+}
+
+// Comment assignment.
+// We build two lists of all subexpressions, preorder and postorder.
+// The preorder list is ordered by start location, with outer expressions first.
+// The postorder list is ordered by end location, with outer expressions last.
+// We use the preorder list to assign each whole-line comment to the syntax
+// immediately following it, and we use the postorder list to assign each
+// end-of-line comment to the syntax immediately preceding it.
+
+// order walks the expression adding it and its subexpressions to the
+// preorder and postorder lists.
+func (in *input) order(x Expr) {
+ if x != nil {
+ in.pre = append(in.pre, x)
+ }
+ switch x := x.(type) {
+ default:
+ panic(fmt.Errorf("order: unexpected type %T", x))
+ case nil:
+ // nothing
+ case *LParen, *RParen:
+ // nothing
+ case *CommentBlock:
+ // nothing
+ case *Line:
+ // nothing
+ case *FileSyntax:
+ for _, stmt := range x.Stmt {
+ in.order(stmt)
+ }
+ case *LineBlock:
+ in.order(&x.LParen)
+ for _, l := range x.Line {
+ in.order(l)
+ }
+ in.order(&x.RParen)
+ }
+ if x != nil {
+ in.post = append(in.post, x)
+ }
+}
+
+// assignComments attaches comments to nearby syntax.
+func (in *input) assignComments() {
+ const debug = false
+
+ // Generate preorder and postorder lists.
+ in.order(in.file)
+
+ // Split into whole-line comments and suffix comments.
+ var line, suffix []Comment
+ for _, com := range in.comments {
+ if com.Suffix {
+ suffix = append(suffix, com)
+ } else {
+ line = append(line, com)
+ }
+ }
+
+ if debug {
+ for _, c := range line {
+ fmt.Fprintf(os.Stderr, "LINE %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
+ }
+ }
+
+ // Assign line comments to syntax immediately following.
+ for _, x := range in.pre {
+ start, _ := x.Span()
+ if debug {
+ fmt.Printf("pre %T :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte)
+ }
+ xcom := x.Comment()
+ for len(line) > 0 && start.Byte >= line[0].Start.Byte {
+ if debug {
+ fmt.Fprintf(os.Stderr, "ASSIGN LINE %q #%d\n", line[0].Token, line[0].Start.Byte)
+ }
+ xcom.Before = append(xcom.Before, line[0])
+ line = line[1:]
+ }
+ }
+
+ // Remaining line comments go at end of file.
+ in.file.After = append(in.file.After, line...)
+
+ if debug {
+ for _, c := range suffix {
+ fmt.Fprintf(os.Stderr, "SUFFIX %q :%d:%d #%d\n", c.Token, c.Start.Line, c.Start.LineRune, c.Start.Byte)
+ }
+ }
+
+ // Assign suffix comments to syntax immediately before.
+ for i := len(in.post) - 1; i >= 0; i-- {
+ x := in.post[i]
+
+ start, end := x.Span()
+ if debug {
+ fmt.Printf("post %T :%d:%d #%d :%d:%d #%d\n", x, start.Line, start.LineRune, start.Byte, end.Line, end.LineRune, end.Byte)
+ }
+
+ // Do not assign suffix comments to end of line block or whole file.
+ // Instead assign them to the last element inside.
+ switch x.(type) {
+ case *FileSyntax:
+ continue
+ }
+
+ // Do not assign suffix comments to something that starts
+ // on an earlier line, so that in
+ //
+ // x ( y
+ // z ) // comment
+ //
+ // we assign the comment to z and not to x ( ... ).
+ if start.Line != end.Line {
+ continue
+ }
+ xcom := x.Comment()
+ for len(suffix) > 0 && end.Byte <= suffix[len(suffix)-1].Start.Byte {
+ if debug {
+ fmt.Fprintf(os.Stderr, "ASSIGN SUFFIX %q #%d\n", suffix[len(suffix)-1].Token, suffix[len(suffix)-1].Start.Byte)
+ }
+ xcom.Suffix = append(xcom.Suffix, suffix[len(suffix)-1])
+ suffix = suffix[:len(suffix)-1]
+ }
+ }
+
+ // We assigned suffix comments in reverse.
+ // If multiple suffix comments were appended to the same
+ // expression node, they are now in reverse. Fix that.
+ for _, x := range in.post {
+ reverseComments(x.Comment().Suffix)
+ }
+
+ // Remaining suffix comments go at beginning of file.
+ in.file.Before = append(in.file.Before, suffix...)
+}
+
+// reverseComments reverses the []Comment list.
+func reverseComments(list []Comment) {
+ for i, j := 0, len(list)-1; i < j; i, j = i+1, j-1 {
+ list[i], list[j] = list[j], list[i]
+ }
+}
+
+func (in *input) parseFile() {
+ in.file = new(FileSyntax)
+ var sym symType
+ var cb *CommentBlock
+ for {
+ tok := in.lex(&sym)
+ switch tok {
+ case '\n':
+ if cb != nil {
+ in.file.Stmt = append(in.file.Stmt, cb)
+ cb = nil
+ }
+ case _COMMENT:
+ if cb == nil {
+ cb = &CommentBlock{Start: sym.pos}
+ }
+ com := cb.Comment()
+ com.Before = append(com.Before, Comment{Start: sym.pos, Token: sym.text})
+ case _EOF:
+ if cb != nil {
+ in.file.Stmt = append(in.file.Stmt, cb)
+ }
+ return
+ default:
+ in.parseStmt(&sym)
+ if cb != nil {
+ in.file.Stmt[len(in.file.Stmt)-1].Comment().Before = cb.Before
+ cb = nil
+ }
+ }
+ }
+}
+
+func (in *input) parseStmt(sym *symType) {
+ start := sym.pos
+ end := sym.endPos
+ token := []string{sym.text}
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case '\n', _EOF, _EOL:
+ in.file.Stmt = append(in.file.Stmt, &Line{
+ Start: start,
+ Token: token,
+ End: end,
+ })
+ return
+ case '(':
+ in.file.Stmt = append(in.file.Stmt, in.parseLineBlock(start, token, sym))
+ return
+ default:
+ token = append(token, sym.text)
+ end = sym.endPos
+ }
+ }
+}
+
+func (in *input) parseLineBlock(start Position, token []string, sym *symType) *LineBlock {
+ x := &LineBlock{
+ Start: start,
+ Token: token,
+ LParen: LParen{Pos: sym.pos},
+ }
+ var comments []Comment
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case _EOL:
+ // ignore
+ case '\n':
+ if len(comments) == 0 && len(x.Line) > 0 || len(comments) > 0 && comments[len(comments)-1].Token != "" {
+ comments = append(comments, Comment{})
+ }
+ case _COMMENT:
+ comments = append(comments, Comment{Start: sym.pos, Token: sym.text})
+ case _EOF:
+ in.Error(fmt.Sprintf("syntax error (unterminated block started at %s:%d:%d)", in.filename, x.Start.Line, x.Start.LineRune))
+ case ')':
+ x.RParen.Before = comments
+ x.RParen.Pos = sym.pos
+ tok = in.lex(sym)
+ if tok != '\n' && tok != _EOF && tok != _EOL {
+ in.Error("syntax error (expected newline after closing paren)")
+ }
+ return x
+ default:
+ l := in.parseLine(sym)
+ x.Line = append(x.Line, l)
+ l.Comment().Before = comments
+ comments = nil
+ }
+ }
+}
+
+func (in *input) parseLine(sym *symType) *Line {
+ start := sym.pos
+ end := sym.endPos
+ token := []string{sym.text}
+ for {
+ tok := in.lex(sym)
+ switch tok {
+ case '\n', _EOF, _EOL:
+ return &Line{
+ Start: start,
+ Token: token,
+ End: end,
+ }
+ default:
+ token = append(token, sym.text)
+ end = sym.endPos
+ }
+ }
+}
+
+const (
+ _EOF = -(1 + iota)
+ _EOL
+ _IDENT
+ _STRING
+ _COMMENT
+)
diff --git a/src/cmd/go/internal/modfile/read_test.go b/src/cmd/go/internal/modfile/read_test.go
new file mode 100644
index 0000000000..2c617b82ae
--- /dev/null
+++ b/src/cmd/go/internal/modfile/read_test.go
@@ -0,0 +1,306 @@
+// Copyright 2018 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 modfile
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+// exists reports whether the named file exists.
+func exists(name string) bool {
+ _, err := os.Stat(name)
+ return err == nil
+}
+
+// Test that reading and then writing the golden files
+// does not change their output.
+func TestPrintGolden(t *testing.T) {
+ outs, err := filepath.Glob("testdata/*.golden")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, out := range outs {
+ testPrint(t, out, out)
+ }
+}
+
+// testPrint is a helper for testing the printer.
+// It reads the file named in, reformats it, and compares
+// the result to the file named out.
+func testPrint(t *testing.T, in, out string) {
+ data, err := ioutil.ReadFile(in)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ golden, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ base := "testdata/" + filepath.Base(in)
+ f, err := parse(in, data)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ ndata := Format(f)
+
+ if !bytes.Equal(ndata, golden) {
+ t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
+ tdiff(t, string(golden), string(ndata))
+ return
+ }
+}
+
+// Test that when files in the testdata directory are parsed
+// and printed and parsed again, we get the same parse tree
+// both times.
+func TestPrintParse(t *testing.T) {
+ outs, err := filepath.Glob("testdata/*")
+ if err != nil {
+ t.Fatal(err)
+ }
+ for _, out := range outs {
+ data, err := ioutil.ReadFile(out)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+
+ base := "testdata/" + filepath.Base(out)
+ f, err := parse(base, data)
+ if err != nil {
+ t.Errorf("parsing original: %v", err)
+ continue
+ }
+
+ ndata := Format(f)
+ f2, err := parse(base, ndata)
+ if err != nil {
+ t.Errorf("parsing reformatted: %v", err)
+ continue
+ }
+
+ eq := eqchecker{file: base}
+ if err := eq.check(f, f2); err != nil {
+ t.Errorf("not equal (parse/Format/parse): %v", err)
+ }
+
+ pf1, err := Parse(base, data, nil)
+ if err != nil {
+ switch base {
+ case "testdata/replace2.in", "testdata/gopkg.in.golden":
+ t.Errorf("should parse %v: %v", base, err)
+ }
+ }
+ if err == nil {
+ pf2, err := Parse(base, ndata, nil)
+ if err != nil {
+ t.Errorf("Parsing reformatted: %v", err)
+ continue
+ }
+ eq := eqchecker{file: base}
+ if err := eq.check(pf1, pf2); err != nil {
+ t.Errorf("not equal (parse/Format/Parse): %v", err)
+ }
+
+ ndata2, err := pf1.Format()
+ if err != nil {
+ t.Errorf("reformat: %v", err)
+ }
+ pf3, err := Parse(base, ndata2, nil)
+ if err != nil {
+ t.Errorf("Parsing reformatted2: %v", err)
+ continue
+ }
+ eq = eqchecker{file: base}
+ if err := eq.check(pf1, pf3); err != nil {
+ t.Errorf("not equal (Parse/Format/Parse): %v", err)
+ }
+ ndata = ndata2
+ }
+
+ if strings.HasSuffix(out, ".in") {
+ golden, err := ioutil.ReadFile(strings.TrimSuffix(out, ".in") + ".golden")
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if !bytes.Equal(ndata, golden) {
+ t.Errorf("formatted %s incorrectly: diff shows -golden, +ours", base)
+ tdiff(t, string(golden), string(ndata))
+ return
+ }
+ }
+ }
+}
+
+// An eqchecker holds state for checking the equality of two parse trees.
+type eqchecker struct {
+ file string
+ pos Position
+}
+
+// errorf returns an error described by the printf-style format and arguments,
+// inserting the current file position before the error text.
+func (eq *eqchecker) errorf(format string, args ...interface{}) error {
+ return fmt.Errorf("%s:%d: %s", eq.file, eq.pos.Line,
+ fmt.Sprintf(format, args...))
+}
+
+// check checks that v and w represent the same parse tree.
+// If not, it returns an error describing the first difference.
+func (eq *eqchecker) check(v, w interface{}) error {
+ return eq.checkValue(reflect.ValueOf(v), reflect.ValueOf(w))
+}
+
+var (
+ posType = reflect.TypeOf(Position{})
+ commentsType = reflect.TypeOf(Comments{})
+)
+
+// checkValue checks that v and w represent the same parse tree.
+// If not, it returns an error describing the first difference.
+func (eq *eqchecker) checkValue(v, w reflect.Value) error {
+ // inner returns the innermost expression for v.
+ // if v is a non-nil interface value, it returns the concrete
+ // value in the interface.
+ inner := func(v reflect.Value) reflect.Value {
+ for {
+ if v.Kind() == reflect.Interface && !v.IsNil() {
+ v = v.Elem()
+ continue
+ }
+ break
+ }
+ return v
+ }
+
+ v = inner(v)
+ w = inner(w)
+ if v.Kind() == reflect.Invalid && w.Kind() == reflect.Invalid {
+ return nil
+ }
+ if v.Kind() == reflect.Invalid {
+ return eq.errorf("nil interface became %s", w.Type())
+ }
+ if w.Kind() == reflect.Invalid {
+ return eq.errorf("%s became nil interface", v.Type())
+ }
+
+ if v.Type() != w.Type() {
+ return eq.errorf("%s became %s", v.Type(), w.Type())
+ }
+
+ if p, ok := v.Interface().(Expr); ok {
+ eq.pos, _ = p.Span()
+ }
+
+ switch v.Kind() {
+ default:
+ return eq.errorf("unexpected type %s", v.Type())
+
+ case reflect.Bool, reflect.Int, reflect.String:
+ vi := v.Interface()
+ wi := w.Interface()
+ if vi != wi {
+ return eq.errorf("%v became %v", vi, wi)
+ }
+
+ case reflect.Slice:
+ vl := v.Len()
+ wl := w.Len()
+ for i := 0; i < vl || i < wl; i++ {
+ if i >= vl {
+ return eq.errorf("unexpected %s", w.Index(i).Type())
+ }
+ if i >= wl {
+ return eq.errorf("missing %s", v.Index(i).Type())
+ }
+ if err := eq.checkValue(v.Index(i), w.Index(i)); err != nil {
+ return err
+ }
+ }
+
+ case reflect.Struct:
+ // Fields in struct must match.
+ t := v.Type()
+ n := t.NumField()
+ for i := 0; i < n; i++ {
+ tf := t.Field(i)
+ switch {
+ default:
+ if err := eq.checkValue(v.Field(i), w.Field(i)); err != nil {
+ return err
+ }
+
+ case tf.Type == posType: // ignore positions
+ case tf.Type == commentsType: // ignore comment assignment
+ }
+ }
+
+ case reflect.Ptr, reflect.Interface:
+ if v.IsNil() != w.IsNil() {
+ if v.IsNil() {
+ return eq.errorf("unexpected %s", w.Elem().Type())
+ }
+ return eq.errorf("missing %s", v.Elem().Type())
+ }
+ if err := eq.checkValue(v.Elem(), w.Elem()); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+// diff returns the output of running diff on b1 and b2.
+func diff(b1, b2 []byte) (data []byte, err error) {
+ f1, err := ioutil.TempFile("", "testdiff")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f1.Name())
+ defer f1.Close()
+
+ f2, err := ioutil.TempFile("", "testdiff")
+ if err != nil {
+ return nil, err
+ }
+ defer os.Remove(f2.Name())
+ defer f2.Close()
+
+ f1.Write(b1)
+ f2.Write(b2)
+
+ data, err = exec.Command("diff", "-u", f1.Name(), f2.Name()).CombinedOutput()
+ if len(data) > 0 {
+ // diff exits with a non-zero status when the files don't match.
+ // Ignore that failure as long as we get output.
+ err = nil
+ }
+ return
+}
+
+// tdiff logs the diff output to t.Error.
+func tdiff(t *testing.T, a, b string) {
+ data, err := diff([]byte(a), []byte(b))
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ t.Error(string(data))
+}
diff --git a/src/cmd/go/internal/modfile/rule.go b/src/cmd/go/internal/modfile/rule.go
new file mode 100644
index 0000000000..5a784a3a33
--- /dev/null
+++ b/src/cmd/go/internal/modfile/rule.go
@@ -0,0 +1,507 @@
+// Copyright 2018 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 modfile
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "path/filepath"
+ "sort"
+ "strconv"
+ "strings"
+ "unicode"
+
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+type File struct {
+ Module *Module
+ Require []*Require
+ Exclude []*Exclude
+ Replace []*Replace
+
+ Syntax *FileSyntax
+}
+
+type Module struct {
+ Mod module.Version
+ Major string
+}
+
+type Require struct {
+ Mod module.Version
+ Syntax *Line
+}
+
+type Exclude struct {
+ Mod module.Version
+ Syntax *Line
+}
+
+type Replace struct {
+ Old module.Version
+ New module.Version
+
+ Syntax *Line
+}
+
+func (f *File) AddModuleStmt(path string) {
+ f.Module = &Module{
+ Mod: module.Version{Path: path},
+ }
+ if f.Syntax == nil {
+ f.Syntax = new(FileSyntax)
+ }
+ f.Syntax.Stmt = append(f.Syntax.Stmt, &Line{
+ Token: []string{"module", AutoQuote(path)},
+ })
+}
+
+func (f *File) AddComment(text string) {
+ if f.Syntax == nil {
+ f.Syntax = new(FileSyntax)
+ }
+ f.Syntax.Stmt = append(f.Syntax.Stmt, &CommentBlock{
+ Comments: Comments{
+ Before: []Comment{
+ {
+ Token: text,
+ },
+ },
+ },
+ })
+}
+
+type VersionFixer func(path, version string) (string, error)
+
+func Parse(file string, data []byte, fix VersionFixer) (*File, error) {
+ fs, err := parse(file, data)
+ if err != nil {
+ return nil, err
+ }
+ f := &File{
+ Syntax: fs,
+ }
+
+ var errs bytes.Buffer
+ for _, x := range fs.Stmt {
+ switch x := x.(type) {
+ case *Line:
+ f.add(&errs, x, x.Token[0], x.Token[1:], fix)
+
+ case *LineBlock:
+ if len(x.Token) > 1 {
+ fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
+ continue
+ }
+ switch x.Token[0] {
+ default:
+ fmt.Fprintf(&errs, "%s:%d: unknown block type: %s\n", file, x.Start.Line, strings.Join(x.Token, " "))
+ continue
+ case "module", "require", "exclude", "replace":
+ for _, l := range x.Line {
+ f.add(&errs, l, x.Token[0], l.Token, fix)
+ }
+ }
+ }
+ }
+
+ if errs.Len() > 0 {
+ return nil, errors.New(strings.TrimRight(errs.String(), "\n"))
+ }
+ return f, nil
+}
+
+func (f *File) add(errs *bytes.Buffer, line *Line, verb string, args []string, fix VersionFixer) {
+ // TODO: We should pass in a flag saying whether this module is a dependency.
+ // If so, we should ignore all unknown directives and not attempt to parse
+ // replace and exclude either. They don't matter, and it will work better for
+ // forward compatibility if we can depend on modules that have local changes.
+
+ // TODO: For the target module (not dependencies), maybe we should
+ // relax the semver requirement and rewrite the file with updated info
+ // after resolving any versions. That would let people type commit hashes
+ // or tags or branch names, and then vgo would fix them.
+
+ switch verb {
+ default:
+ fmt.Fprintf(errs, "%s:%d: unknown directive: %s\n", f.Syntax.Name, line.Start.Line, verb)
+ case "module":
+ if f.Module != nil {
+ fmt.Fprintf(errs, "%s:%d: repeated module statement\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ f.Module = new(Module)
+ if len(args) != 1 {
+
+ fmt.Fprintf(errs, "%s:%d: usage: module module/path [version]\n", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ f.Module.Mod = module.Version{Path: s}
+ case "require", "exclude":
+ if len(args) != 2 {
+ fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3\n", f.Syntax.Name, line.Start.Line, verb)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ old := args[1]
+ v, err := parseVersion(s, &args[1], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %q: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ v1, err := moduleMajorVersion(s)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ if v2 := semver.Major(v); v1 != v2 && (v1 != "v1" || v2 != "v0") {
+ fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, v1, v2, v)
+ return
+ }
+ if verb == "require" {
+ f.Require = append(f.Require, &Require{
+ Mod: module.Version{Path: s, Version: v},
+ Syntax: line,
+ })
+ } else {
+ f.Exclude = append(f.Exclude, &Exclude{
+ Mod: module.Version{Path: s, Version: v},
+ Syntax: line,
+ })
+ }
+ case "replace":
+ if len(args) < 4 || len(args) > 5 || args[2] != "=>" {
+ fmt.Fprintf(errs, "%s:%d: usage: %s module/path v1.2.3 => other/module v1.4\n\t or %s module/path v1.2.3 => ../local/directory", f.Syntax.Name, line.Start.Line, verb, verb)
+ return
+ }
+ s, err := parseString(&args[0])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ old := args[1]
+ v, err := parseVersion(s, &args[1], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ v1, err := moduleMajorVersion(s)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ if v2 := semver.Major(v); v1 != v2 && (v1 != "v1" || v2 != "v0") {
+ fmt.Fprintf(errs, "%s:%d: invalid module: %s should be %s, not %s (%s)\n", f.Syntax.Name, line.Start.Line, s, v1, v2, v)
+ return
+ }
+ ns, err := parseString(&args[3])
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid quoted string: %v\n", f.Syntax.Name, line.Start.Line, err)
+ return
+ }
+ nv := ""
+ if len(args) == 4 {
+ if !isDirectoryPath(ns) {
+ fmt.Fprintf(errs, "%s:%d: replacement module without version must be directory path (rooted or starting with ./ or ../)", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ if filepath.Separator == '/' && strings.Contains(ns, `\`) {
+ fmt.Fprintf(errs, "%s:%d: replacement directory appears to be Windows path (on a non-windows system)", f.Syntax.Name, line.Start.Line)
+ return
+ }
+ }
+ if len(args) == 5 {
+ old := args[4]
+ nv, err = parseVersion(ns, &args[4], fix)
+ if err != nil {
+ fmt.Fprintf(errs, "%s:%d: invalid module version %v: %v\n", f.Syntax.Name, line.Start.Line, old, err)
+ return
+ }
+ if isDirectoryPath(ns) {
+ fmt.Fprintf(errs, "%s:%d: replacement module directory path %q cannot have version", f.Syntax.Name, line.Start.Line, ns)
+ return
+ }
+ }
+ // TODO: More sanity checks about directories vs module paths.
+ f.Replace = append(f.Replace, &Replace{
+ Old: module.Version{Path: s, Version: v},
+ New: module.Version{Path: ns, Version: nv},
+ Syntax: line,
+ })
+ }
+}
+
+func isDirectoryPath(ns string) bool {
+ // Because go.mod files can move from one system to another,
+ // we check all known path syntaxes, both Unix and Windows.
+ return strings.HasPrefix(ns, "./") || strings.HasPrefix(ns, "../") || strings.HasPrefix(ns, "/") ||
+ strings.HasPrefix(ns, `.\`) || strings.HasPrefix(ns, `..\`) || strings.HasPrefix(ns, `\`) ||
+ len(ns) >= 2 && ('A' <= ns[0] && ns[0] <= 'Z' || 'a' <= ns[0] && ns[0] <= 'z') && ns[1] == ':'
+}
+
+func mustQuote(t string) bool {
+ for _, r := range t {
+ if !unicode.IsPrint(r) || r == ' ' || r == '"' || r == '\'' || r == '`' {
+ return true
+ }
+ }
+ return t == "" || strings.Contains(t, "//") || strings.Contains(t, "/*")
+}
+
+// AutoQuote returns s or, if quoting is required for s to appear in a go.mod,
+// the quotation of s.
+func AutoQuote(s string) string {
+ if mustQuote(s) {
+ return strconv.Quote(s)
+ }
+ return s
+}
+
+func parseString(s *string) (string, error) {
+ t := *s
+ if strings.HasPrefix(t, `"`) {
+ var err error
+ if t, err = strconv.Unquote(t); err != nil {
+ return "", err
+ }
+ } else if strings.ContainsAny(t, "\"'`") {
+ // Other quotes are reserved both for possible future expansion
+ // and to avoid confusion. For example if someone types 'x'
+ // we want that to be a syntax error and not a literal x in literal quotation marks.
+ return "", fmt.Errorf("unquoted string cannot contain quote")
+ }
+ *s = AutoQuote(t)
+ return t, nil
+}
+
+func parseVersion(path string, s *string, fix VersionFixer) (string, error) {
+ t, err := parseString(s)
+ if err != nil {
+ return "", err
+ }
+ if fix != nil {
+ var err error
+ t, err = fix(path, t)
+ if err != nil {
+ return "", err
+ }
+ }
+ if semver.IsValid(t) {
+ *s = semver.Canonical(t)
+ return *s, nil
+ }
+ return "", fmt.Errorf("version must be of the form v1.2.3")
+}
+
+func moduleMajorVersion(p string) (string, error) {
+ if _, _, major, _, ok := ParseGopkgIn(p); ok {
+ return major, nil
+ }
+
+ start := strings.LastIndex(p, "/") + 1
+ v := p[start:]
+ if !isMajorVersion(v) {
+ return "v1", nil
+ }
+ if v[1] == '0' || v == "v1" {
+ return "", fmt.Errorf("module path has invalid version number %s", v)
+ }
+ return v, nil
+}
+
+func isMajorVersion(v string) bool {
+ if len(v) < 2 || v[0] != 'v' {
+ return false
+ }
+ for i := 1; i < len(v); i++ {
+ if v[i] < '0' || '9' < v[i] {
+ return false
+ }
+ }
+ return true
+}
+
+func (f *File) Format() ([]byte, error) {
+ return Format(f.Syntax), nil
+}
+
+func (x *File) AddRequire(path, vers string) {
+ var syntax *Line
+
+ for i, stmt := range x.Syntax.Stmt {
+ switch stmt := stmt.(type) {
+ case *LineBlock:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ syntax = &Line{Token: []string{AutoQuote(path), vers}}
+ stmt.Line = append(stmt.Line, syntax)
+ goto End
+ }
+ case *Line:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ stmt.Token = stmt.Token[1:]
+ syntax = &Line{Token: []string{AutoQuote(path), vers}}
+ x.Syntax.Stmt[i] = &LineBlock{
+ Comments: stmt.Comments,
+ Token: []string{"require"},
+ Line: []*Line{
+ stmt,
+ syntax,
+ },
+ }
+ goto End
+ }
+ }
+ }
+
+ syntax = &Line{Token: []string{"require", AutoQuote(path), vers}}
+ x.Syntax.Stmt = append(x.Syntax.Stmt, syntax)
+
+End:
+ x.Require = append(x.Require, &Require{module.Version{Path: path, Version: vers}, syntax})
+}
+
+func (f *File) SetRequire(req []module.Version) {
+ need := make(map[string]string)
+ for _, m := range req {
+ need[m.Path] = m.Version
+ }
+
+ for _, r := range f.Require {
+ if v, ok := need[r.Mod.Path]; ok {
+ r.Mod.Version = v
+ }
+ }
+
+ var newStmts []Expr
+ for _, stmt := range f.Syntax.Stmt {
+ switch stmt := stmt.(type) {
+ case *LineBlock:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ var newLines []*Line
+ for _, line := range stmt.Line {
+ if p, err := strconv.Unquote(line.Token[0]); err == nil && need[p] != "" {
+ line.Token[1] = need[p]
+ delete(need, p)
+ newLines = append(newLines, line)
+ }
+ }
+ if len(newLines) == 0 {
+ continue // drop stmt
+ }
+ stmt.Line = newLines
+ }
+
+ case *Line:
+ if len(stmt.Token) > 0 && stmt.Token[0] == "require" {
+ if p, err := strconv.Unquote(stmt.Token[1]); err == nil && need[p] != "" {
+ stmt.Token[2] = need[p]
+ delete(need, p)
+ } else {
+ continue // drop stmt
+ }
+ }
+ }
+ newStmts = append(newStmts, stmt)
+ }
+ f.Syntax.Stmt = newStmts
+
+ for path, vers := range need {
+ f.AddRequire(path, vers)
+ }
+ f.SortBlocks()
+}
+
+func (f *File) SortBlocks() {
+ f.removeDups() // otherwise sorting is unsafe
+
+ for _, stmt := range f.Syntax.Stmt {
+ block, ok := stmt.(*LineBlock)
+ if !ok {
+ continue
+ }
+ sort.Slice(block.Line, func(i, j int) bool {
+ li := block.Line[i]
+ lj := block.Line[j]
+ for k := 0; k < len(li.Token) && k < len(lj.Token); k++ {
+ if li.Token[k] != lj.Token[k] {
+ return li.Token[k] < lj.Token[k]
+ }
+ }
+ return len(li.Token) < len(lj.Token)
+ })
+ }
+}
+
+func (f *File) removeDups() {
+ have := make(map[module.Version]bool)
+ kill := make(map[*Line]bool)
+ for _, x := range f.Exclude {
+ if have[x.Mod] {
+ kill[x.Syntax] = true
+ continue
+ }
+ have[x.Mod] = true
+ }
+ var excl []*Exclude
+ for _, x := range f.Exclude {
+ if !kill[x.Syntax] {
+ excl = append(excl, x)
+ }
+ }
+ f.Exclude = excl
+
+ have = make(map[module.Version]bool)
+ // Later replacements take priority over earlier ones.
+ for i := len(f.Replace) - 1; i >= 0; i-- {
+ x := f.Replace[i]
+ if have[x.Old] {
+ kill[x.Syntax] = true
+ continue
+ }
+ have[x.Old] = true
+ }
+ var repl []*Replace
+ for _, x := range f.Replace {
+ if !kill[x.Syntax] {
+ repl = append(repl, x)
+ }
+ }
+ f.Replace = repl
+
+ var stmts []Expr
+ for _, stmt := range f.Syntax.Stmt {
+ switch stmt := stmt.(type) {
+ case *Line:
+ if kill[stmt] {
+ continue
+ }
+ case *LineBlock:
+ var lines []*Line
+ for _, line := range stmt.Line {
+ if !kill[line] {
+ lines = append(lines, line)
+ }
+ }
+ stmt.Line = lines
+ if len(lines) == 0 {
+ continue
+ }
+ }
+ stmts = append(stmts, stmt)
+ }
+ f.Syntax.Stmt = stmts
+}
diff --git a/src/cmd/go/internal/modfile/testdata/block.golden b/src/cmd/go/internal/modfile/testdata/block.golden
new file mode 100644
index 0000000000..4aa2d634fc
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/block.golden
@@ -0,0 +1,29 @@
+// comment
+x "y" z
+
+// block
+block ( // block-eol
+ // x-before-line
+
+ "x" ( y // x-eol
+ "x1"
+ "x2"
+ // line
+ "x3"
+ "x4"
+
+ "x5"
+
+ // y-line
+ "y" // y-eol
+
+ "z" // z-eol
+) // block-eol2
+
+block2 (
+ x
+ y
+ z
+)
+
+// eof
diff --git a/src/cmd/go/internal/modfile/testdata/block.in b/src/cmd/go/internal/modfile/testdata/block.in
new file mode 100644
index 0000000000..1dfae65f5c
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/block.in
@@ -0,0 +1,29 @@
+// comment
+x "y" z
+
+// block
+block ( // block-eol
+ // x-before-line
+
+ "x" ( y // x-eol
+ "x1"
+ "x2"
+ // line
+ "x3"
+ "x4"
+
+ "x5"
+
+ // y-line
+ "y" // y-eol
+
+ "z" // z-eol
+) // block-eol2
+
+
+block2 (x
+ y
+ z
+)
+
+// eof
diff --git a/src/cmd/go/internal/modfile/testdata/comment.golden b/src/cmd/go/internal/modfile/testdata/comment.golden
new file mode 100644
index 0000000000..75f3b84478
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/comment.golden
@@ -0,0 +1,10 @@
+// comment
+module "x" // eol
+
+// mid comment
+
+// comment 2
+// comment 2 line 2
+module "y" // eoy
+
+// comment 3
diff --git a/src/cmd/go/internal/modfile/testdata/comment.in b/src/cmd/go/internal/modfile/testdata/comment.in
new file mode 100644
index 0000000000..bfc2492b26
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/comment.in
@@ -0,0 +1,8 @@
+// comment
+module "x" // eol
+// mid comment
+
+// comment 2
+// comment 2 line 2
+module "y" // eoy
+// comment 3
diff --git a/src/cmd/go/internal/modfile/testdata/empty.golden b/src/cmd/go/internal/modfile/testdata/empty.golden
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/empty.golden
diff --git a/src/cmd/go/internal/modfile/testdata/empty.in b/src/cmd/go/internal/modfile/testdata/empty.in
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/empty.in
diff --git a/src/cmd/go/internal/modfile/testdata/gopkg.in.golden b/src/cmd/go/internal/modfile/testdata/gopkg.in.golden
new file mode 100644
index 0000000000..41669b3a73
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/gopkg.in.golden
@@ -0,0 +1,6 @@
+module x
+
+require (
+ gopkg.in/mgo.v2 v2.0.0-20160818020120-3f83fa500528
+ gopkg.in/yaml.v2 v2.2.1
+)
diff --git a/src/cmd/go/internal/modfile/testdata/module.golden b/src/cmd/go/internal/modfile/testdata/module.golden
new file mode 100644
index 0000000000..78ba94398c
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/module.golden
@@ -0,0 +1 @@
+module abc
diff --git a/src/cmd/go/internal/modfile/testdata/module.in b/src/cmd/go/internal/modfile/testdata/module.in
new file mode 100644
index 0000000000..08f383623f
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/module.in
@@ -0,0 +1 @@
+module "abc"
diff --git a/src/cmd/go/internal/modfile/testdata/replace.golden b/src/cmd/go/internal/modfile/testdata/replace.golden
new file mode 100644
index 0000000000..5d6abcfcda
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/replace.golden
@@ -0,0 +1,5 @@
+module abc
+
+replace xyz v1.2.3 => /tmp/z
+
+replace xyz v1.3.4 => my/xyz v1.3.4-me
diff --git a/src/cmd/go/internal/modfile/testdata/replace.in b/src/cmd/go/internal/modfile/testdata/replace.in
new file mode 100644
index 0000000000..685249946a
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/replace.in
@@ -0,0 +1,5 @@
+module "abc"
+
+replace "xyz" v1.2.3 => "/tmp/z"
+
+replace "xyz" v1.3.4 => "my/xyz" v1.3.4-me
diff --git a/src/cmd/go/internal/modfile/testdata/replace2.golden b/src/cmd/go/internal/modfile/testdata/replace2.golden
new file mode 100644
index 0000000000..1d18a3b461
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/replace2.golden
@@ -0,0 +1,8 @@
+module abc
+
+replace (
+ xyz v1.2.3 => /tmp/z
+ xyz v1.3.4 => my/xyz v1.3.4-me
+ xyz v1.4.5 => "/tmp/my dir"
+ xyz v1.5.6 => my/xyz v1.5.6
+)
diff --git a/src/cmd/go/internal/modfile/testdata/replace2.in b/src/cmd/go/internal/modfile/testdata/replace2.in
new file mode 100644
index 0000000000..78c46694a2
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/replace2.in
@@ -0,0 +1,8 @@
+module "abc"
+
+replace (
+ "xyz" v1.2.3 => "/tmp/z"
+ "xyz" v1.3.4 => "my/xyz" "v1.3.4-me"
+ xyz "v1.4.5" => "/tmp/my dir"
+ xyz v1.5.6 => my/xyz v1.5.6
+)
diff --git a/src/cmd/go/internal/modfile/testdata/rule1.golden b/src/cmd/go/internal/modfile/testdata/rule1.golden
new file mode 100644
index 0000000000..8a5c725894
--- /dev/null
+++ b/src/cmd/go/internal/modfile/testdata/rule1.golden
@@ -0,0 +1,7 @@
+module "x"
+
+module "y"
+
+require "x"
+
+require x
diff --git a/src/cmd/go/internal/modinfo/info.go b/src/cmd/go/internal/modinfo/info.go
new file mode 100644
index 0000000000..6dff2d2c26
--- /dev/null
+++ b/src/cmd/go/internal/modinfo/info.go
@@ -0,0 +1,11 @@
+// Copyright 2018 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 modinfo
+
+type ModulePublic struct {
+ Top bool
+ Path string
+ Version string
+}
diff --git a/src/cmd/go/internal/module/module.go b/src/cmd/go/internal/module/module.go
new file mode 100644
index 0000000000..1e8f74c1af
--- /dev/null
+++ b/src/cmd/go/internal/module/module.go
@@ -0,0 +1,195 @@
+// Copyright 2018 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 module defines the module.Version type
+// along with support code.
+package module
+
+import (
+ "fmt"
+ "strings"
+ "unicode"
+ "unicode/utf8"
+
+ "cmd/go/internal/semver"
+)
+
+// A Version is defined by a module path and version pair.
+type Version struct {
+ Path string
+ Version string
+}
+
+// Check checks that a given module path, version pair is valid.
+// In addition to the path being a valid module path
+// and the version being a valid semantic version,
+// the two must correspond.
+// For example, the path "yaml/v2" only corresponds to
+// semantic versions beginning with "v2.".
+func Check(path, version string) error {
+ if err := CheckPath(path); err != nil {
+ return err
+ }
+ if !semver.IsValid(version) {
+ return fmt.Errorf("malformed semantic version %v", version)
+ }
+ vm := semver.Major(version)
+ _, pathVersion, _ := SplitPathVersion(path)
+
+ if strings.HasPrefix(pathVersion, ".") {
+ // Special-case gopkg.in path requirements.
+ pathVersion = pathVersion[1:] // cut .
+ if vm == pathVersion {
+ return nil
+ }
+ } else {
+ // Standard path requirements.
+ if pathVersion != "" {
+ pathVersion = pathVersion[1:] // cut /
+ }
+ if vm == "v0" || vm == "v1" {
+ vm = ""
+ }
+ if vm == pathVersion {
+ return nil
+ }
+ if pathVersion == "" {
+ pathVersion = "v0 or v1"
+ }
+ }
+ return fmt.Errorf("mismatched module path %v and version %v (want %v)", path, version, pathVersion)
+}
+
+// firstPathOK reports whether r can appear in the first element of a module path.
+// The first element of the path must be an LDH domain name, at least for now.
+func firstPathOK(r rune) bool {
+ return r == '-' || r == '.' ||
+ '0' <= r && r <= '9' ||
+ 'A' <= r && r <= 'Z' ||
+ 'a' <= r && r <= 'z'
+}
+
+// pathOK reports whether r can appear in a module path.
+// Paths must avoid potentially problematic ASCII punctuation
+// and control characters but otherwise can be any Unicode printable character,
+// as defined by Go's IsPrint.
+func pathOK(r rune) bool {
+ if r < utf8.RuneSelf {
+ return r == '+' || r == ',' || r == '-' || r == '.' || r == '/' || r == '_' || r == '~' ||
+ '0' <= r && r <= '9' ||
+ 'A' <= r && r <= 'Z' ||
+ 'a' <= r && r <= 'z'
+ }
+ return unicode.IsPrint(r)
+}
+
+// CheckPath checks that a module path is valid.
+func CheckPath(path string) error {
+ if !utf8.ValidString(path) {
+ return fmt.Errorf("malformed module path %q: invalid UTF-8", path)
+ }
+ if path == "" {
+ return fmt.Errorf("malformed module path %q: empty string", path)
+ }
+
+ i := strings.Index(path, "/")
+ if i < 0 {
+ i = len(path)
+ }
+ if i == 0 {
+ return fmt.Errorf("malformed module path %q: leading slash", path)
+ }
+ if !strings.Contains(path[:i], ".") {
+ return fmt.Errorf("malformed module path %q: missing dot in first path element", path)
+ }
+ if path[i-1] == '.' {
+ return fmt.Errorf("malformed module path %q: trailing dot in first path element", path)
+ }
+ if path[0] == '.' {
+ return fmt.Errorf("malformed module path %q: leading dot in first path element", path)
+ }
+ if path[0] == '-' {
+ return fmt.Errorf("malformed module path %q: leading dash in first path element", path)
+ }
+ if strings.Contains(path, "..") {
+ return fmt.Errorf("malformed module path %q: double dot", path)
+ }
+ if strings.Contains(path, "//") {
+ return fmt.Errorf("malformed module path %q: double slash", path)
+ }
+ for _, r := range path[:i] {
+ if !firstPathOK(r) {
+ return fmt.Errorf("malformed module path %q: invalid char %q in first path element", path, r)
+ }
+ }
+ if path[len(path)-1] == '/' {
+ return fmt.Errorf("malformed module path %q: trailing slash", path)
+ }
+ for _, r := range path {
+ if !pathOK(r) {
+ return fmt.Errorf("malformed module path %q: invalid char %q", path, r)
+ }
+ }
+ if _, _, ok := SplitPathVersion(path); !ok {
+ return fmt.Errorf("malformed module path %q: invalid version %s", path, path[strings.LastIndex(path, "/")+1:])
+ }
+ return nil
+}
+
+// SplitPathVersion returns prefix and major version such that prefix+pathMajor == path
+// and version is either empty or "/vN" for N >= 2.
+// As a special case, gopkg.in paths are recognized directly;
+// they require ".vN" instead of "/vN", and for all N, not just N >= 2.
+func SplitPathVersion(path string) (prefix, pathMajor string, ok bool) {
+ if strings.HasPrefix(path, "gopkg.in/") {
+ return splitGopkgIn(path)
+ }
+
+ i := len(path)
+ dot := false
+ for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9' || path[i-1] == '.') {
+ if path[i-1] == '.' {
+ dot = true
+ }
+ i--
+ }
+ if i <= 1 || path[i-1] != 'v' || path[i-2] != '/' {
+ return path, "", true
+ }
+ prefix, pathMajor = path[:i-2], path[i-2:]
+ if dot || len(pathMajor) <= 2 || pathMajor[2] == '0' || pathMajor == "/v1" {
+ return path, "", false
+ }
+ return prefix, pathMajor, true
+}
+
+// splitGopkgIn is like SplitPathVersion but only for gopkg.in paths.
+func splitGopkgIn(path string) (prefix, pathMajor string, ok bool) {
+ if !strings.HasPrefix(path, "gopkg.in/") {
+ return path, "", false
+ }
+ i := len(path)
+ for i > 0 && ('0' <= path[i-1] && path[i-1] <= '9') {
+ i--
+ }
+ if i <= 1 || path[i-1] != 'v' || path[i-2] != '.' {
+ // All gopkg.in paths must end in vN for some N.
+ return path, "", false
+ }
+ prefix, pathMajor = path[:i-2], path[i-2:]
+ if len(pathMajor) <= 2 || pathMajor[2] == '0' && pathMajor != ".v0" {
+ return path, "", false
+ }
+ return prefix, pathMajor, true
+}
+
+// MatchPathMajor reports whether the semantic version v
+// matches the path major version pathMajor.
+func MatchPathMajor(v, pathMajor string) bool {
+ m := semver.Major(v)
+ if pathMajor == "" {
+ return m == "v0" || m == "v1"
+ }
+ return (pathMajor[0] == '/' || pathMajor[0] == '.') && m == pathMajor[1:]
+}
diff --git a/src/cmd/go/internal/module/module_test.go b/src/cmd/go/internal/module/module_test.go
new file mode 100644
index 0000000000..6142a9e048
--- /dev/null
+++ b/src/cmd/go/internal/module/module_test.go
@@ -0,0 +1,184 @@
+// Copyright 2018 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 module
+
+import "testing"
+
+var checkTests = []struct {
+ path string
+ version string
+ ok bool
+}{
+ {"rsc.io/quote", "0.1.0", false},
+ {"rsc io/quote", "v1.0.0", false},
+
+ {"github.com/go-yaml/yaml", "v0.8.0", true},
+ {"github.com/go-yaml/yaml", "v1.0.0", true},
+ {"github.com/go-yaml/yaml", "v2.0.0", false},
+ {"github.com/go-yaml/yaml", "v2.1.5", false},
+ {"github.com/go-yaml/yaml", "v3.0.0", false},
+
+ {"github.com/go-yaml/yaml/v2", "v1.0.0", false},
+ {"github.com/go-yaml/yaml/v2", "v2.0.0", true},
+ {"github.com/go-yaml/yaml/v2", "v2.1.5", true},
+ {"github.com/go-yaml/yaml/v2", "v3.0.0", false},
+
+ {"gopkg.in/yaml.v0", "v0.8.0", true},
+ {"gopkg.in/yaml.v0", "v1.0.0", false},
+ {"gopkg.in/yaml.v0", "v2.0.0", false},
+ {"gopkg.in/yaml.v0", "v2.1.5", false},
+ {"gopkg.in/yaml.v0", "v3.0.0", false},
+
+ {"gopkg.in/yaml.v1", "v0.8.0", false},
+ {"gopkg.in/yaml.v1", "v1.0.0", true},
+ {"gopkg.in/yaml.v1", "v2.0.0", false},
+ {"gopkg.in/yaml.v1", "v2.1.5", false},
+ {"gopkg.in/yaml.v1", "v3.0.0", false},
+
+ {"gopkg.in/yaml.v2", "v1.0.0", false},
+ {"gopkg.in/yaml.v2", "v2.0.0", true},
+ {"gopkg.in/yaml.v2", "v2.1.5", true},
+ {"gopkg.in/yaml.v2", "v3.0.0", false},
+}
+
+func TestCheck(t *testing.T) {
+ for _, tt := range checkTests {
+ err := Check(tt.path, tt.version)
+ if tt.ok && err != nil {
+ t.Errorf("Check(%q, %q) = %v, wanted nil error", tt.path, tt.version, err)
+ } else if !tt.ok && err == nil {
+ t.Errorf("Check(%q, %q) succeeded, wanted error", tt.path, tt.version)
+ }
+ }
+}
+
+var checkPathTests = []struct {
+ path string
+ ok bool
+}{
+ {"x.y/z", true},
+ {"x.y", true},
+
+ {"", false},
+ {"x.y/\xFFz", false},
+ {"/x.y/z", false},
+ {"x./z", false},
+ {".x/z", false},
+ {"-x/z", false},
+ {"x..y/z", false},
+ {"x.y/z/../../w", false},
+ {"x.y//z", false},
+ {"x.y/z//w", false},
+ {"x.y/z/", false},
+
+ {"x.y/z/v0", false},
+ {"x.y/z/v1", false},
+ {"x.y/z/v2", true},
+ {"x.y/z/v2.0", false},
+
+ {"!x.y/z", false},
+ {"_x.y/z", false},
+ {"x.y!/z", false},
+ {"x.y\"/z", false},
+ {"x.y#/z", false},
+ {"x.y$/z", false},
+ {"x.y%/z", false},
+ {"x.y&/z", false},
+ {"x.y'/z", false},
+ {"x.y(/z", false},
+ {"x.y)/z", false},
+ {"x.y*/z", false},
+ {"x.y+/z", false},
+ {"x.y,/z", false},
+ {"x.y-/z", true},
+ {"x.y./zt", false},
+ {"x.y:/z", false},
+ {"x.y;/z", false},
+ {"x.y</z", false},
+ {"x.y=/z", false},
+ {"x.y>/z", false},
+ {"x.y?/z", false},
+ {"x.y@/z", false},
+ {"x.y[/z", false},
+ {"x.y\\/z", false},
+ {"x.y]/z", false},
+ {"x.y^/z", false},
+ {"x.y_/z", false},
+ {"x.y`/z", false},
+ {"x.y{/z", false},
+ {"x.y}/z", false},
+ {"x.y~/z", false},
+ {"x.y/z!", false},
+ {"x.y/z\"", false},
+ {"x.y/z#", false},
+ {"x.y/z$", false},
+ {"x.y/z%", false},
+ {"x.y/z&", false},
+ {"x.y/z'", false},
+ {"x.y/z(", false},
+ {"x.y/z)", false},
+ {"x.y/z*", false},
+ {"x.y/z+", true},
+ {"x.y/z,", true},
+ {"x.y/z-", true},
+ {"x.y/z.t", true},
+ {"x.y/z/t", true},
+ {"x.y/z:", false},
+ {"x.y/z;", false},
+ {"x.y/z<", false},
+ {"x.y/z=", false},
+ {"x.y/z>", false},
+ {"x.y/z?", false},
+ {"x.y/z@", false},
+ {"x.y/z[", false},
+ {"x.y/z\\", false},
+ {"x.y/z]", false},
+ {"x.y/z^", false},
+ {"x.y/z_", true},
+ {"x.y/z`", false},
+ {"x.y/z{", false},
+ {"x.y/z}", false},
+ {"x.y/z~", true},
+}
+
+func TestCheckPath(t *testing.T) {
+ for _, tt := range checkPathTests {
+ err := CheckPath(tt.path)
+ if tt.ok && err != nil {
+ t.Errorf("CheckPath(%q) = %v, wanted nil error", tt.path, err)
+ } else if !tt.ok && err == nil {
+ t.Errorf("CheckPath(%q) succeeded, wanted error", tt.path)
+ }
+ }
+}
+
+var splitPathVersionTests = []struct {
+ pathPrefix string
+ version string
+}{
+ {"x.y/z", ""},
+ {"x.y/z", "/v2"},
+ {"x.y/z", "/v3"},
+ {"gopkg.in/yaml", ".v0"},
+ {"gopkg.in/yaml", ".v1"},
+ {"gopkg.in/yaml", ".v2"},
+ {"gopkg.in/yaml", ".v3"},
+}
+
+func TestSplitPathVersion(t *testing.T) {
+ for _, tt := range splitPathVersionTests {
+ pathPrefix, version, ok := SplitPathVersion(tt.pathPrefix + tt.version)
+ if pathPrefix != tt.pathPrefix || version != tt.version || !ok {
+ t.Errorf("SplitPathVersion(%q) = %q, %q, %v, want %q, %q, true", tt.pathPrefix+tt.version, pathPrefix, version, ok, tt.pathPrefix, tt.version)
+ }
+ }
+
+ for _, tt := range checkPathTests {
+ pathPrefix, version, ok := SplitPathVersion(tt.path)
+ if pathPrefix+version != tt.path {
+ t.Errorf("SplitPathVersion(%q) = %q, %q, %v, doesn't add to input", tt.path, pathPrefix, version, ok)
+ }
+ }
+}
diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go
new file mode 100644
index 0000000000..47670ff5a6
--- /dev/null
+++ b/src/cmd/go/internal/mvs/mvs.go
@@ -0,0 +1,308 @@
+// Copyright 2018 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 mvs implements Minimal Version Selection.
+// See https://research.swtch.com/vgo-mvs.
+package mvs
+
+import (
+ "fmt"
+ "sort"
+
+ "cmd/go/internal/module"
+)
+
+type Reqs interface {
+ Required(m module.Version) ([]module.Version, error)
+ Max(v1, v2 string) string
+ Latest(path string) (module.Version, error)
+ Previous(m module.Version) (module.Version, error)
+}
+
+type MissingModuleError struct {
+ Module module.Version
+}
+
+func (e *MissingModuleError) Error() string {
+ return fmt.Sprintf("missing module: %v", e.Module)
+}
+
+// BuildList returns the build list for the target module.
+func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
+ return buildList(target, reqs, nil, nil)
+}
+
+func buildList(target module.Version, reqs Reqs, uses map[module.Version][]module.Version, vers map[string]string) ([]module.Version, error) {
+ var (
+ min = map[string]string{target.Path: target.Version}
+ todo = []module.Version{target}
+ seen = map[module.Version]bool{target: true}
+ )
+ for len(todo) > 0 {
+ m := todo[len(todo)-1]
+ todo = todo[:len(todo)-1]
+ required, _ := reqs.Required(m)
+ for _, r := range required {
+ if uses != nil {
+ uses[r] = append(uses[r], m)
+ }
+ if !seen[r] {
+ if v, ok := min[r.Path]; !ok {
+ min[r.Path] = r.Version
+ } else if max := reqs.Max(v, r.Version); max != v {
+ min[r.Path] = max
+ }
+ todo = append(todo, r)
+ seen[r] = true
+ }
+ }
+ }
+
+ if min[target.Path] != target.Version {
+ panic("unbuildable") // TODO
+ }
+
+ if vers == nil {
+ vers = make(map[string]string)
+ }
+ list := []module.Version{target}
+ for i := 0; i < len(list); i++ {
+ m := list[i]
+ required, err := reqs.Required(m)
+ if err != nil {
+ // TODO: Check error is decent.
+ return nil, err
+ }
+ for _, r := range required {
+ v := min[r.Path]
+ if reqs.Max(v, r.Version) != v {
+ panic("mistake") // TODO
+ }
+ if _, ok := vers[r.Path]; !ok {
+ vers[r.Path] = v
+ list = append(list, module.Version{Path: r.Path, Version: v})
+ }
+ }
+ }
+ tail := list[1:]
+ sort.Slice(tail, func(i, j int) bool {
+ return tail[i].Path < tail[j].Path
+ })
+ return list, nil
+}
+
+// Req returns the minimal requirement list for the target module
+// that result in the given build list.
+func Req(target module.Version, list []module.Version, reqs Reqs) ([]module.Version, error) {
+ // Compute postorder, cache requirements.
+ var postorder []module.Version
+ reqCache := map[module.Version][]module.Version{}
+ reqCache[target] = nil
+ var walk func(module.Version) error
+ walk = func(m module.Version) error {
+ _, ok := reqCache[m]
+ if ok {
+ return nil
+ }
+ required, err := reqs.Required(m)
+ if err != nil {
+ return err
+ }
+ reqCache[m] = required
+ for _, m1 := range required {
+ if err := walk(m1); err != nil {
+ return err
+ }
+ }
+ postorder = append(postorder, m)
+ return nil
+ }
+ for _, m := range list {
+ if err := walk(m); err != nil {
+ return nil, err
+ }
+ }
+
+ // Walk modules in reverse post-order, only adding those not implied already.
+ have := map[string]string{}
+ walk = func(m module.Version) error {
+ if v, ok := have[m.Path]; ok && reqs.Max(m.Version, v) == v {
+ return nil
+ }
+ have[m.Path] = m.Version
+ for _, m1 := range reqCache[m] {
+ walk(m1)
+ }
+ return nil
+ }
+ max := map[string]string{}
+ for _, m := range list {
+ if max[m.Path] == "" {
+ max[m.Path] = m.Version
+ } else {
+ max[m.Path] = reqs.Max(m.Version, max[m.Path])
+ }
+ }
+ var min []module.Version
+ for i := len(postorder) - 1; i >= 0; i-- {
+ m := postorder[i]
+ if max[m.Path] != m.Version {
+ // Older version.
+ continue
+ }
+ if have[m.Path] != m.Version {
+ min = append(min, m)
+ walk(m)
+ }
+ }
+ sort.Slice(min, func(i, j int) bool {
+ return min[i].Path < min[j].Path
+ })
+ return min, nil
+}
+
+// UpgradeAll returns a build list for the target module
+// in which every module is upgraded to its latest version.
+func UpgradeAll(target module.Version, reqs Reqs) ([]module.Version, error) {
+ have := map[string]bool{target.Path: true}
+ list := []module.Version{target}
+ for i := 0; i < len(list); i++ {
+ m := list[i]
+ required, err := reqs.Required(m)
+ if err != nil {
+ panic(err) // TODO
+ }
+ for _, r := range required {
+ latest, err := reqs.Latest(r.Path)
+ if err != nil {
+ panic(err) // TODO
+ }
+ if reqs.Max(latest.Version, r.Version) != latest.Version {
+ panic("mistake") // TODO
+ }
+ if !have[r.Path] {
+ have[r.Path] = true
+ list = append(list, module.Version{Path: r.Path, Version: latest.Version})
+ }
+ }
+ }
+ tail := list[1:]
+ sort.Slice(tail, func(i, j int) bool {
+ return tail[i].Path < tail[j].Path
+ })
+ return list, nil
+}
+
+// Upgrade returns a build list for the target module
+// in which the given additional modules are upgraded.
+func Upgrade(target module.Version, reqs Reqs, upgrade ...module.Version) ([]module.Version, error) {
+ list, err := reqs.Required(target)
+ if err != nil {
+ panic(err) // TODO
+ }
+ // TODO: Maybe if an error is given,
+ // rerun with BuildList(upgrade[0], reqs) etc
+ // to find which ones are the buggy ones.
+ list = append([]module.Version(nil), list...)
+ list = append(list, upgrade...)
+ return BuildList(target, &override{target, list, reqs})
+}
+
+// Downgrade returns a build list for the target module
+// in which the given additional modules are downgraded.
+func Downgrade(target module.Version, reqs Reqs, downgrade ...module.Version) ([]module.Version, error) {
+ list, err := reqs.Required(target)
+ if err != nil {
+ panic(err) // TODO
+ }
+ max := make(map[string]string)
+ for _, r := range list {
+ max[r.Path] = r.Version
+ }
+ for _, d := range downgrade {
+ if v, ok := max[d.Path]; !ok || reqs.Max(v, d.Version) != d.Version {
+ max[d.Path] = d.Version
+ }
+ }
+
+ var (
+ added = make(map[module.Version]bool)
+ rdeps = make(map[module.Version][]module.Version)
+ excluded = make(map[module.Version]bool)
+ )
+ var exclude func(module.Version)
+ exclude = func(m module.Version) {
+ if excluded[m] {
+ return
+ }
+ excluded[m] = true
+ for _, p := range rdeps[m] {
+ exclude(p)
+ }
+ }
+ var add func(module.Version)
+ add = func(m module.Version) {
+ if added[m] {
+ return
+ }
+ added[m] = true
+ if v, ok := max[m.Path]; ok && reqs.Max(m.Version, v) != v {
+ exclude(m)
+ return
+ }
+ list, err := reqs.Required(m)
+ if err != nil {
+ panic(err) // TODO
+ }
+ for _, r := range list {
+ add(r)
+ if excluded[r] {
+ exclude(m)
+ return
+ }
+ rdeps[r] = append(rdeps[r], m)
+ }
+ }
+
+ var out []module.Version
+ out = append(out, target)
+List:
+ for _, r := range list {
+ add(r)
+ for excluded[r] {
+ p, err := reqs.Previous(r)
+ if err != nil {
+ return nil, err // TODO
+ }
+ // If the target version is a pseudo-version, it may not be
+ // included when iterating over prior versions using reqs.Previous.
+ // Insert it into the right place in the iteration.
+ // If v is excluded, p should be returned again by reqs.Previous on the next iteration.
+ if v := max[r.Path]; reqs.Max(v, r.Version) != v && reqs.Max(p.Version, v) != p.Version {
+ p.Version = v
+ }
+ if p.Version == "none" {
+ continue List
+ }
+ add(p)
+ r = p
+ }
+ out = append(out, r)
+ }
+
+ return out, nil
+}
+
+type override struct {
+ target module.Version
+ list []module.Version
+ Reqs
+}
+
+func (r *override) Required(m module.Version) ([]module.Version, error) {
+ if m == r.target {
+ return r.list, nil
+ }
+ return r.Reqs.Required(m)
+}
diff --git a/src/cmd/go/internal/mvs/mvs_test.go b/src/cmd/go/internal/mvs/mvs_test.go
new file mode 100644
index 0000000000..0fd55e4e45
--- /dev/null
+++ b/src/cmd/go/internal/mvs/mvs_test.go
@@ -0,0 +1,377 @@
+// Copyright 2018 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 mvs
+
+import (
+ "reflect"
+ "strings"
+ "testing"
+
+ "cmd/go/internal/module"
+)
+
+var tests = `
+# Scenario from blog.
+name: blog
+A: B1 C2
+B1: D3
+C1: D2
+C2: D4
+C3: D5
+C4: G1
+D2: E1
+D3: E2
+D4: E2 F1
+D5: E2
+G1: C4
+A2: B1 C4 D4
+build A: A B1 C2 D4 E2 F1
+upgrade* A: A B1 C4 D5 E2 G1
+upgrade A C4: A B1 C4 D4 E2 F1 G1
+downgrade A2 D2: A2 C4 D2
+
+name: trim
+A: B1 C2
+B1: D3
+C2: B2
+B2:
+build A: A B2 C2
+
+# Cross-dependency between D and E.
+# No matter how it arises, should get result of merging all build lists via max,
+# which leads to including both D2 and E2.
+
+name: cross1
+A: B C
+B: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross1V
+A: B2 C D2 E1
+B1:
+B2: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B2 C D2 E2
+
+name: cross1U
+A: B1 C
+B1:
+B2: D1
+C: D2
+D1: E2
+D2: E1
+build A: A B1 C D2 E1
+upgrade A B2: A B2 C D2 E2
+
+name: cross1R
+A: B C
+B: D2
+C: D1
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross1X
+A: B C
+B: D1 E2
+C: D2
+D1: E2
+D2: E1
+build A: A B C D2 E2
+
+name: cross2
+A: B D2
+B: D1
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross2X
+A: B D2
+B: D1 E2
+C: D2
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross3
+A: B D2 E1
+B: D1
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+name: cross3X
+A: B D2 E1
+B: D1 E2
+D1: E2
+D2: E1
+build A: A B D2 E2
+
+# Should not get E2 here, because B has been updated
+# not to depend on D1 anymore.
+name: cross4
+A1: B1 D2
+A2: B2 D2
+B1: D1
+B2: D2
+D1: E2
+D2: E1
+build A1: A1 B1 D2 E2
+build A2: A2 B2 D2 E1
+
+# But the upgrade from A1 preserves the E2 dep explicitly.
+upgrade A1 B2: A1 B2 D2 E2
+upgradereq A1 B2: B2 E2
+
+name: cross5
+A: D1
+D1: E2
+D2: E1
+build A: A D1 E2
+upgrade* A: A D2 E2
+upgrade A D2: A D2 E2
+upgradereq A D2: D2 E2
+
+name: cross6
+A: D2
+D1: E2
+D2: E1
+build A: A D2 E1
+upgrade* A: A D2 E2
+upgrade A E2: A D2 E2
+
+name: cross7
+A: B C
+B: D1
+C: E1
+D1: E2
+E1: D2
+build A: A B C D2 E2
+
+name: down1
+A: B2
+B1: C1
+B2: C2
+build A: A B2 C2
+downgrade A C1: A B1
+
+name: down2
+A: B2 E2
+B1:
+B2: C2 F2
+C1:
+D1:
+C2: D2 E2
+D2: B2
+E2: D2
+E1:
+F1:
+downgrade A F1: A B1 E1
+
+name: down3
+A:
+
+# golang.org/issue/25542.
+name: noprev1
+A: B4 C2
+B2.hidden:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+
+name: noprev2
+A: B4 C2
+B2.hidden:
+B1:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+
+name: noprev3
+A: B4 C2
+B3:
+B2.hidden:
+C2:
+downgrade A B2.hidden: A B2.hidden C2
+`
+
+func Test(t *testing.T) {
+ var (
+ name string
+ reqs reqsMap
+ fns []func(*testing.T)
+ )
+ flush := func() {
+ if name != "" {
+ t.Run(name, func(t *testing.T) {
+ for _, fn := range fns {
+ fn(t)
+ }
+ })
+ }
+ }
+ m := func(s string) module.Version {
+ return module.Version{Path: s[:1], Version: s[1:]}
+ }
+ ms := func(list []string) []module.Version {
+ var mlist []module.Version
+ for _, s := range list {
+ mlist = append(mlist, m(s))
+ }
+ return mlist
+ }
+ checkList := func(t *testing.T, desc string, list []module.Version, err error, val string) {
+ if err != nil {
+ t.Fatalf("%s: %v", desc, err)
+ }
+ vs := ms(strings.Fields(val))
+ if !reflect.DeepEqual(list, vs) {
+ t.Errorf("%s = %v, want %v", desc, list, vs)
+ }
+ }
+
+ for _, line := range strings.Split(tests, "\n") {
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+ i := strings.Index(line, ":")
+ if i < 0 {
+ t.Fatalf("missing colon: %q", line)
+ }
+ key := strings.TrimSpace(line[:i])
+ val := strings.TrimSpace(line[i+1:])
+ if key == "" {
+ t.Fatalf("missing key: %q", line)
+ }
+ kf := strings.Fields(key)
+ switch kf[0] {
+ case "name":
+ if len(kf) != 1 {
+ t.Fatalf("name takes no arguments: %q", line)
+ }
+ flush()
+ reqs = make(reqsMap)
+ fns = nil
+ name = val
+ continue
+ case "build":
+ if len(kf) != 2 {
+ t.Fatalf("build takes one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := BuildList(m(kf[1]), reqs)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgrade*":
+ if len(kf) != 2 {
+ t.Fatalf("upgrade* takes one argument: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := UpgradeAll(m(kf[1]), reqs)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgradereq":
+ if len(kf) < 2 {
+ t.Fatalf("upgrade takes at least one arguments: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...)
+ if err == nil {
+ list, err = Req(m(kf[1]), list, reqs)
+ }
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "upgrade":
+ if len(kf) < 2 {
+ t.Fatalf("upgrade takes at least one arguments: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Upgrade(m(kf[1]), reqs, ms(kf[2:])...)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ case "downgrade":
+ if len(kf) < 2 {
+ t.Fatalf("downgrade takes at least one arguments: %q", line)
+ }
+ fns = append(fns, func(t *testing.T) {
+ list, err := Downgrade(m(kf[1]), reqs, ms(kf[1:])...)
+ checkList(t, key, list, err, val)
+ })
+ continue
+ }
+ if len(kf) == 1 && 'A' <= key[0] && key[0] <= 'Z' {
+ var rs []module.Version
+ for _, f := range strings.Fields(val) {
+ r := m(f)
+ if reqs[r] == nil {
+ reqs[r] = []module.Version{}
+ }
+ rs = append(rs, r)
+ }
+ reqs[m(key)] = rs
+ continue
+ }
+ t.Fatalf("bad line: %q", line)
+ }
+ flush()
+}
+
+type reqsMap map[module.Version][]module.Version
+
+func (r reqsMap) Max(v1, v2 string) string {
+ if v1 == "none" {
+ return v2
+ }
+ if v2 == "none" {
+ return v1
+ }
+ if v1 < v2 {
+ return v2
+ }
+ return v1
+}
+
+func (r reqsMap) Latest(path string) (module.Version, error) {
+ var m module.Version
+ for k := range r {
+ if k.Path == path && m.Version < k.Version {
+ m = k
+ }
+ }
+ if m.Path == "" {
+ return module.Version{}, &MissingModuleError{module.Version{Path: path, Version: ""}}
+ }
+ return m, nil
+}
+
+func (r reqsMap) Previous(m module.Version) (module.Version, error) {
+ var p module.Version
+ for k := range r {
+ if k.Path == m.Path && p.Version < k.Version && k.Version < m.Version && !strings.HasSuffix(k.Version, ".hidden") {
+ p = k
+ }
+ }
+ if p.Path == "" {
+ return module.Version{Path: m.Path, Version: "none"}, nil
+ }
+ return p, nil
+}
+
+func (r reqsMap) Required(m module.Version) ([]module.Version, error) {
+ rr, ok := r[m]
+ if !ok {
+ return nil, &MissingModuleError{m}
+ }
+ return rr, nil
+}
diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go
new file mode 100644
index 0000000000..42a6be0520
--- /dev/null
+++ b/src/cmd/go/internal/search/search.go
@@ -0,0 +1,423 @@
+// Copyright 2017 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 search
+
+import (
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "fmt"
+ "go/build"
+ "log"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strings"
+)
+
+// AllPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func AllPackages(pattern string) []string {
+ pkgs := MatchPackages(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+// AllPackagesInFS is like allPackages but is passed a pattern
+// beginning ./ or ../, meaning it should scan the tree rooted
+// at the given directory. There are ... in the pattern too.
+func AllPackagesInFS(pattern string) []string {
+ pkgs := MatchPackagesInFS(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+// MatchPackages returns a list of package paths matching pattern
+// (see go help packages for pattern syntax).
+func MatchPackages(pattern string) []string {
+ match := func(string) bool { return true }
+ treeCanMatch := func(string) bool { return true }
+ if !IsMetaPackage(pattern) {
+ match = MatchPattern(pattern)
+ treeCanMatch = TreeCanMatchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !cfg.BuildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+ var pkgs []string
+
+ for _, src := range cfg.BuildContext.SrcDirs() {
+ if (pattern == "std" || pattern == "cmd") && src != cfg.GOROOTsrc {
+ continue
+ }
+ src = filepath.Clean(src) + string(filepath.Separator)
+ root := src
+ if pattern == "cmd" {
+ root += "cmd" + string(filepath.Separator)
+ }
+ filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || path == src {
+ return nil
+ }
+
+ want := true
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ want = false
+ }
+
+ name := filepath.ToSlash(path[len(src):])
+ if pattern == "std" && (!IsStandardImportPath(name) || name == "cmd") {
+ // The name "std" is only the standard library.
+ // If the name is cmd, it's the root of the command tree.
+ want = false
+ }
+ if !treeCanMatch(name) {
+ want = false
+ }
+
+ if !fi.IsDir() {
+ if fi.Mode()&os.ModeSymlink != 0 && want {
+ if target, err := os.Stat(path); err == nil && target.IsDir() {
+ fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
+ }
+ }
+ return nil
+ }
+ if !want {
+ return filepath.SkipDir
+ }
+
+ if have[name] {
+ return nil
+ }
+ have[name] = true
+ if !match(name) {
+ return nil
+ }
+ pkg, err := cfg.BuildContext.ImportDir(path, 0)
+ if err != nil {
+ if _, noGo := err.(*build.NoGoError); noGo {
+ return nil
+ }
+ }
+
+ // If we are expanding "cmd", skip main
+ // packages under cmd/vendor. At least as of
+ // March, 2017, there is one there for the
+ // vendored pprof tool.
+ if pattern == "cmd" && strings.HasPrefix(pkg.ImportPath, "cmd/vendor") && pkg.Name == "main" {
+ return nil
+ }
+
+ pkgs = append(pkgs, name)
+ return nil
+ })
+ }
+ return pkgs
+}
+
+var modRoot string
+
+func SetModRoot(dir string) {
+ modRoot = dir
+}
+
+// MatchPackagesInFS returns a list of package paths matching pattern,
+// which must begin with ./ or ../
+// (see go help packages for pattern syntax).
+func MatchPackagesInFS(pattern string) []string {
+ // Find directory to begin the scan.
+ // Could be smarter but this one optimization
+ // is enough for now, since ... is usually at the
+ // end of a path.
+ i := strings.Index(pattern, "...")
+ dir, _ := path.Split(pattern[:i])
+
+ // pattern begins with ./ or ../.
+ // path.Clean will discard the ./ but not the ../.
+ // We need to preserve the ./ for pattern matching
+ // and in the returned import paths.
+ prefix := ""
+ if strings.HasPrefix(pattern, "./") {
+ prefix = "./"
+ }
+ match := MatchPattern(pattern)
+
+ if modRoot != "" {
+ abs, err := filepath.Abs(dir)
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+ if !hasFilepathPrefix(abs, modRoot) {
+ base.Fatalf("go: pattern %s refers to dir %s, outside module root %s", pattern, abs, modRoot)
+ return nil
+ }
+ }
+
+ var pkgs []string
+ filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
+ if err != nil || !fi.IsDir() {
+ return nil
+ }
+ if path == dir {
+ // filepath.Walk starts at dir and recurses. For the recursive case,
+ // the path is the result of filepath.Join, which calls filepath.Clean.
+ // The initial case is not Cleaned, though, so we do this explicitly.
+ //
+ // This converts a path like "./io/" to "io". Without this step, running
+ // "cd $GOROOT/src; go list ./io/..." would incorrectly skip the io
+ // package, because prepending the prefix "./" to the unclean path would
+ // result in "././io", and match("././io") returns false.
+ path = filepath.Clean(path)
+ }
+
+ // Avoid .foo, _foo, and testdata directory trees, but do not avoid "." or "..".
+ _, elem := filepath.Split(path)
+ dot := strings.HasPrefix(elem, ".") && elem != "." && elem != ".."
+ if dot || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ return filepath.SkipDir
+ }
+
+ name := prefix + filepath.ToSlash(path)
+ if !match(name) {
+ return nil
+ }
+
+ // We keep the directory if we can import it, or if we can't import it
+ // due to invalid Go source files. This means that directories containing
+ // parse errors will be built (and fail) instead of being silently skipped
+ // as not matching the pattern. Go 1.5 and earlier skipped, but that
+ // behavior means people miss serious mistakes.
+ // See golang.org/issue/11407.
+ if p, err := cfg.BuildContext.ImportDir(path, 0); err != nil && (p == nil || len(p.InvalidGoFiles) == 0) {
+ if _, noGo := err.(*build.NoGoError); !noGo {
+ log.Print(err)
+ }
+ return nil
+ }
+ pkgs = append(pkgs, name)
+ return nil
+ })
+ return pkgs
+}
+
+// TreeCanMatchPattern(pattern)(name) reports whether
+// name or children of name can possibly match pattern.
+// Pattern is the same limited glob accepted by matchPattern.
+func TreeCanMatchPattern(pattern string) func(name string) bool {
+ wildCard := false
+ if i := strings.Index(pattern, "..."); i >= 0 {
+ wildCard = true
+ pattern = pattern[:i]
+ }
+ return func(name string) bool {
+ return len(name) <= len(pattern) && hasPathPrefix(pattern, name) ||
+ wildCard && strings.HasPrefix(name, pattern)
+ }
+}
+
+// MatchPattern(pattern)(name) reports whether
+// name matches pattern. Pattern is a limited glob
+// pattern in which '...' means 'any string' and there
+// is no other special syntax.
+// Unfortunately, there are two special cases. Quoting "go help packages":
+//
+// First, /... at the end of the pattern can match an empty string,
+// so that net/... matches both net and packages in its subdirectories, like net/http.
+// Second, any slash-separted pattern element containing a wildcard never
+// participates in a match of the "vendor" element in the path of a vendored
+// package, so that ./... does not match packages in subdirectories of
+// ./vendor or ./mycode/vendor, but ./vendor/... and ./mycode/vendor/... do.
+// Note, however, that a directory named vendor that itself contains code
+// is not a vendored package: cmd/vendor would be a command named vendor,
+// and the pattern cmd/... matches it.
+func MatchPattern(pattern string) func(name string) bool {
+ // Convert pattern to regular expression.
+ // The strategy for the trailing /... is to nest it in an explicit ? expression.
+ // The strategy for the vendor exclusion is to change the unmatchable
+ // vendor strings to a disallowed code point (vendorChar) and to use
+ // "(anything but that codepoint)*" as the implementation of the ... wildcard.
+ // This is a bit complicated but the obvious alternative,
+ // namely a hand-written search like in most shell glob matchers,
+ // is too easy to make accidentally exponential.
+ // Using package regexp guarantees linear-time matching.
+
+ const vendorChar = "\x00"
+
+ if strings.Contains(pattern, vendorChar) {
+ return func(name string) bool { return false }
+ }
+
+ re := regexp.QuoteMeta(pattern)
+ re = replaceVendor(re, vendorChar)
+ switch {
+ case strings.HasSuffix(re, `/`+vendorChar+`/\.\.\.`):
+ re = strings.TrimSuffix(re, `/`+vendorChar+`/\.\.\.`) + `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case re == vendorChar+`/\.\.\.`:
+ re = `(/vendor|/` + vendorChar + `/\.\.\.)`
+ case strings.HasSuffix(re, `/\.\.\.`):
+ re = strings.TrimSuffix(re, `/\.\.\.`) + `(/\.\.\.)?`
+ }
+ re = strings.Replace(re, `\.\.\.`, `[^`+vendorChar+`]*`, -1)
+
+ reg := regexp.MustCompile(`^` + re + `$`)
+
+ return func(name string) bool {
+ if strings.Contains(name, vendorChar) {
+ return false
+ }
+ return reg.MatchString(replaceVendor(name, vendorChar))
+ }
+}
+
+// replaceVendor returns the result of replacing
+// non-trailing vendor path elements in x with repl.
+func replaceVendor(x, repl string) string {
+ if !strings.Contains(x, "vendor") {
+ return x
+ }
+ elem := strings.Split(x, "/")
+ for i := 0; i < len(elem)-1; i++ {
+ if elem[i] == "vendor" {
+ elem[i] = repl
+ }
+ }
+ return strings.Join(elem, "/")
+}
+
+// ImportPaths returns the import paths to use for the given command line.
+func ImportPaths(args []string) []string {
+ args = CleanImportPaths(args)
+ var out []string
+ for _, a := range args {
+ if IsMetaPackage(a) {
+ out = append(out, AllPackages(a)...)
+ continue
+ }
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, AllPackagesInFS(a)...)
+ } else {
+ out = append(out, AllPackages(a)...)
+ }
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// CleanImportPaths returns the import paths to use for the given
+// command line, but it does no wildcard expansion.
+func CleanImportPaths(args []string) []string {
+ if len(args) == 0 {
+ return []string{"."}
+ }
+ var out []string
+ for _, a := range args {
+ // Arguments are supposed to be import paths, but
+ // as a courtesy to Windows developers, rewrite \ to /
+ // in command-line arguments. Handles .\... and so on.
+ if filepath.Separator == '\\' {
+ a = strings.Replace(a, `\`, `/`, -1)
+ }
+
+ // Put argument in canonical form, but preserve leading ./.
+ if strings.HasPrefix(a, "./") {
+ a = "./" + path.Clean(a)
+ if a == "./." {
+ a = "."
+ }
+ } else {
+ a = path.Clean(a)
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// ImportPathsNoDotExpansion returns the import paths to use for the given
+// command line, but it does no ... expansion.
+// TODO(vgo): Delete once old go get is gone.
+func ImportPathsNoDotExpansion(args []string) []string {
+ args = CleanImportPaths(args)
+ var out []string
+ for _, a := range args {
+ if IsMetaPackage(a) {
+ out = append(out, AllPackages(a)...)
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// IsMetaPackage checks if name is a reserved package name that expands to multiple packages.
+func IsMetaPackage(name string) bool {
+ return name == "std" || name == "cmd" || name == "all"
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+ }
+}
+
+// hasFilepathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasFilepathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == filepath.Separator {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == filepath.Separator && s[:len(prefix)] == prefix
+ }
+}
+
+// IsStandardImportPath reports whether $GOROOT/src/path should be considered
+// part of the standard distribution. For historical reasons we allow people to add
+// their own code to $GOROOT instead of using $GOPATH, but we assume that
+// code will start with a domain name (dot in the first element).
+//
+// Note that this function is meant to evaluate whether a directory found in GOROOT
+// should be treated as part of the standard library. It should not be used to decide
+// that a directory found in GOPATH should be rejected: directories in GOPATH
+// need not have dots in the first element, and they just take their chances
+// with future collisions in the standard library.
+func IsStandardImportPath(path string) bool {
+ i := strings.Index(path, "/")
+ if i < 0 {
+ i = len(path)
+ }
+ elem := path[:i]
+ return !strings.Contains(elem, ".")
+}
diff --git a/src/cmd/go/internal/load/match_test.go b/src/cmd/go/internal/search/search_test.go
index b8d67dac74..0bef765fa4 100644
--- a/src/cmd/go/internal/load/match_test.go
+++ b/src/cmd/go/internal/search/search_test.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package load
+package search
import (
"strings"
@@ -65,8 +65,8 @@ var matchPatternTests = `
`
func TestMatchPattern(t *testing.T) {
- testPatterns(t, "matchPattern", matchPatternTests, func(pattern, name string) bool {
- return matchPattern(pattern)(name)
+ testPatterns(t, "MatchPattern", matchPatternTests, func(pattern, name string) bool {
+ return MatchPattern(pattern)(name)
})
}
@@ -106,8 +106,8 @@ var treeCanMatchPatternTests = `
`
func TestTreeCanMatchPattern(t *testing.T) {
- testPatterns(t, "treeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
- return treeCanMatchPattern(pattern)(name)
+ testPatterns(t, "TreeCanMatchPattern", treeCanMatchPatternTests, func(pattern, name string) bool {
+ return TreeCanMatchPattern(pattern)(name)
})
}
diff --git a/src/cmd/go/internal/semver/semver.go b/src/cmd/go/internal/semver/semver.go
new file mode 100644
index 0000000000..ecc5300c8c
--- /dev/null
+++ b/src/cmd/go/internal/semver/semver.go
@@ -0,0 +1,351 @@
+// Copyright 2018 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 semver implements comparison of semantic version strings.
+// In this package, semantic version strings must begin with a leading "v",
+// as in "v1.0.0".
+//
+// The general form of a semantic version string accepted by this package is
+//
+// vMAJOR[.MINOR[.PATCH[-PRERELEASE][+BUILD]]]
+//
+// where square brackets indicate optional parts of the syntax;
+// MAJOR, MINOR, and PATCH are decimal integers without extra leading zeros;
+// PRERELEASE and BUILD are each a series of non-empty dot-separated identifiers
+// using only alphanumeric characters and hyphens; and
+// all-numeric PRERELEASE identifiers must not have leading zeros.
+//
+// This package follows Semantic Versioning 2.0.0 (see semver.org)
+// with two exceptions. First, it requires the "v" prefix. Second, it recognizes
+// vMAJOR and vMAJOR.MINOR (with no prerelease or build suffixes)
+// as shorthands for vMAJOR.0.0 and vMAJOR.MINOR.0.
+package semver
+
+// parsed returns the parsed form of a semantic version string.
+type parsed struct {
+ major string
+ minor string
+ patch string
+ short string
+ prerelease string
+ build string
+ err string
+}
+
+// IsValid reports whether v is a valid semantic version string.
+func IsValid(v string) bool {
+ _, ok := parse(v)
+ return ok
+}
+
+// Canonical returns the canonical formatting of the semantic version v.
+// It fills in any missing .MINOR or .PATCH and discards build metadata.
+// Two semantic versions compare equal only if their canonical formattings
+// are identical strings.
+// The canonical invalid semantic version is the empty string.
+func Canonical(v string) string {
+ p, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ if p.build != "" {
+ return v[:len(v)-len(p.build)]
+ }
+ if p.short != "" {
+ return v + p.short
+ }
+ return v
+}
+
+// Major returns the major version prefix of the semantic version v.
+// For example, Major("v2.1.0") == "v2".
+// If v is an invalid semantic version string, Major returns the empty string.
+func Major(v string) string {
+ pv, ok := parse(v)
+ if !ok {
+ return ""
+ }
+ return v[:1+len(pv.major)]
+}
+
+// Compare returns an integer comparing two versions according to
+// according to semantic version precedence.
+// The result will be 0 if v == w, -1 if v < w, or +1 if v > w.
+//
+// An invalid semantic version string is considered less than a valid one.
+// All invalid semantic version strings compare equal to each other.
+func Compare(v, w string) int {
+ pv, ok1 := parse(v)
+ pw, ok2 := parse(w)
+ if !ok1 && !ok2 {
+ return 0
+ }
+ if !ok1 {
+ return -1
+ }
+ if !ok2 {
+ return +1
+ }
+ if c := compareInt(pv.major, pw.major); c != 0 {
+ return c
+ }
+ if c := compareInt(pv.minor, pw.minor); c != 0 {
+ return c
+ }
+ if c := compareInt(pv.patch, pw.patch); c != 0 {
+ return c
+ }
+ return comparePrerelease(pv.prerelease, pw.prerelease)
+}
+
+// Max canonicalizes its arguments and then returns the version string
+// that compares greater.
+func Max(v, w string) string {
+ v = Canonical(v)
+ w = Canonical(w)
+ if Compare(v, w) > 0 {
+ return v
+ }
+ return w
+}
+
+func parse(v string) (p parsed, ok bool) {
+ if v == "" || v[0] != 'v' {
+ p.err = "missing v prefix"
+ return
+ }
+ p.major, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad major version"
+ return
+ }
+ if v == "" {
+ p.minor = "0"
+ p.patch = "0"
+ p.short = ".0.0"
+ return
+ }
+ if v[0] != '.' {
+ p.err = "bad minor prefix"
+ ok = false
+ return
+ }
+ p.minor, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad minor version"
+ return
+ }
+ if v == "" {
+ p.patch = "0"
+ p.short = ".0"
+ return
+ }
+ if v[0] != '.' {
+ p.err = "bad patch prefix"
+ ok = false
+ return
+ }
+ p.patch, v, ok = parseInt(v[1:])
+ if !ok {
+ p.err = "bad patch version"
+ return
+ }
+ if len(v) > 0 && v[0] == '-' {
+ p.prerelease, v, ok = parsePrerelease(v)
+ if !ok {
+ p.err = "bad prerelease"
+ return
+ }
+ }
+ if len(v) > 0 && v[0] == '+' {
+ p.build, v, ok = parseBuild(v)
+ if !ok {
+ p.err = "bad build"
+ return
+ }
+ }
+ if v != "" {
+ p.err = "junk on end"
+ ok = false
+ return
+ }
+ ok = true
+ return
+}
+
+func parseInt(v string) (t, rest string, ok bool) {
+ if v == "" {
+ return
+ }
+ if v[0] < '0' || '9' < v[0] {
+ return
+ }
+ i := 1
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ if v[0] == '0' && i != 1 {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func parsePrerelease(v string) (t, rest string, ok bool) {
+ // "A pre-release version MAY be denoted by appending a hyphen and
+ // a series of dot separated identifiers immediately following the patch version.
+ // Identifiers MUST comprise only ASCII alphanumerics and hyphen [0-9A-Za-z-].
+ // Identifiers MUST NOT be empty. Numeric identifiers MUST NOT include leading zeroes."
+ if v == "" || v[0] != '-' {
+ return
+ }
+ i := 1
+ start := 1
+ for i < len(v) && v[i] != '+' {
+ if !isIdentChar(v[i]) && v[i] != '.' {
+ return
+ }
+ if v[i] == '.' {
+ if start == i || isBadNum(v[start:i]) {
+ return
+ }
+ start = i + 1
+ }
+ i++
+ }
+ if start == i || isBadNum(v[start:i]) {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func parseBuild(v string) (t, rest string, ok bool) {
+ if v == "" || v[0] != '+' {
+ return
+ }
+ i := 1
+ start := 1
+ for i < len(v) {
+ if !isIdentChar(v[i]) {
+ return
+ }
+ if v[i] == '.' {
+ if start == i {
+ return
+ }
+ start = i + 1
+ }
+ i++
+ }
+ if start == i {
+ return
+ }
+ return v[:i], v[i:], true
+}
+
+func isIdentChar(c byte) bool {
+ return 'A' <= c && c <= 'Z' || 'a' <= c && c <= 'z' || '0' <= c && c <= '9' || c == '-'
+}
+
+func isBadNum(v string) bool {
+ i := 0
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ return i == len(v) && i > 1 && v[0] == '0'
+}
+
+func isNum(v string) bool {
+ i := 0
+ for i < len(v) && '0' <= v[i] && v[i] <= '9' {
+ i++
+ }
+ return i == len(v)
+}
+
+func compareInt(x, y string) int {
+ if x == y {
+ return 0
+ }
+ if len(x) < len(y) {
+ return -1
+ }
+ if len(x) > len(y) {
+ return +1
+ }
+ if x < y {
+ return -1
+ } else {
+ return +1
+ }
+}
+
+func comparePrerelease(x, y string) int {
+ // "When major, minor, and patch are equal, a pre-release version has
+ // lower precedence than a normal version.
+ // Example: 1.0.0-alpha < 1.0.0.
+ // Precedence for two pre-release versions with the same major, minor,
+ // and patch version MUST be determined by comparing each dot separated
+ // identifier from left to right until a difference is found as follows:
+ // identifiers consisting of only digits are compared numerically and
+ // identifiers with letters or hyphens are compared lexically in ASCII
+ // sort order. Numeric identifiers always have lower precedence than
+ // non-numeric identifiers. A larger set of pre-release fields has a
+ // higher precedence than a smaller set, if all of the preceding
+ // identifiers are equal.
+ // Example: 1.0.0-alpha < 1.0.0-alpha.1 < 1.0.0-alpha.beta <
+ // 1.0.0-beta < 1.0.0-beta.2 < 1.0.0-beta.11 < 1.0.0-rc.1 < 1.0.0."
+ if x == y {
+ return 0
+ }
+ if x == "" {
+ return +1
+ }
+ if y == "" {
+ return -1
+ }
+ for x != "" && y != "" {
+ x = x[1:] // skip - or .
+ y = y[1:] // skip - or .
+ var dx, dy string
+ dx, x = nextIdent(x)
+ dy, y = nextIdent(y)
+ if dx != dy {
+ ix := isNum(dx)
+ iy := isNum(dy)
+ if ix != iy {
+ if ix {
+ return -1
+ } else {
+ return +1
+ }
+ }
+ if ix {
+ if len(dx) < len(dy) {
+ return -1
+ }
+ if len(dx) > len(dy) {
+ return +1
+ }
+ }
+ if dx < dy {
+ return -1
+ } else {
+ return +1
+ }
+ }
+ }
+ if x == "" {
+ return -1
+ } else {
+ return +1
+ }
+}
+
+func nextIdent(x string) (dx, rest string) {
+ i := 0
+ for i < len(x) && x[i] != '.' {
+ i++
+ }
+ return x[:i], x[i:]
+}
diff --git a/src/cmd/go/internal/semver/semver_test.go b/src/cmd/go/internal/semver/semver_test.go
new file mode 100644
index 0000000000..7a697f6800
--- /dev/null
+++ b/src/cmd/go/internal/semver/semver_test.go
@@ -0,0 +1,123 @@
+// Copyright 2018 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 semver
+
+import (
+ "strings"
+ "testing"
+)
+
+var tests = []struct {
+ in string
+ out string
+}{
+ {"bad", ""},
+ {"v1-pre", ""},
+ {"v1+meta", ""},
+ {"v1-pre+meta", ""},
+ {"v1.2-pre", ""},
+ {"v1.2+meta", ""},
+ {"v1.2-pre+meta", ""},
+ {"v1.0.0-alpha", "v1.0.0-alpha"},
+ {"v1.0.0-alpha.1", "v1.0.0-alpha.1"},
+ {"v1.0.0-alpha.beta", "v1.0.0-alpha.beta"},
+ {"v1.0.0-beta", "v1.0.0-beta"},
+ {"v1.0.0-beta.2", "v1.0.0-beta.2"},
+ {"v1.0.0-beta.11", "v1.0.0-beta.11"},
+ {"v1.0.0-rc.1", "v1.0.0-rc.1"},
+ {"v1", "v1.0.0"},
+ {"v1.0", "v1.0.0"},
+ {"v1.0.0", "v1.0.0"},
+ {"v1.2", "v1.2.0"},
+ {"v1.2.0", "v1.2.0"},
+ {"v1.2.3-456", "v1.2.3-456"},
+ {"v1.2.3-456.789", "v1.2.3-456.789"},
+ {"v1.2.3-456-789", "v1.2.3-456-789"},
+ {"v1.2.3-456a", "v1.2.3-456a"},
+ {"v1.2.3-pre", "v1.2.3-pre"},
+ {"v1.2.3-pre+meta", "v1.2.3-pre"},
+ {"v1.2.3-pre.1", "v1.2.3-pre.1"},
+ {"v1.2.3-zzz", "v1.2.3-zzz"},
+ {"v1.2.3", "v1.2.3"},
+ {"v1.2.3+meta", "v1.2.3"},
+}
+
+func TestIsValid(t *testing.T) {
+ for _, tt := range tests {
+ ok := IsValid(tt.in)
+ if ok != (tt.out != "") {
+ t.Errorf("IsValid(%q) = %v, want %v", tt.in, ok, !ok)
+ }
+ }
+}
+
+func TestCanonical(t *testing.T) {
+ for _, tt := range tests {
+ out := Canonical(tt.in)
+ if out != tt.out {
+ t.Errorf("Canonical(%q) = %q, want %q", tt.in, out, tt.out)
+ }
+ }
+}
+
+func TestMajor(t *testing.T) {
+ for _, tt := range tests {
+ out := Major(tt.in)
+ want := ""
+ if i := strings.Index(tt.out, "."); i >= 0 {
+ want = tt.out[:i]
+ }
+ if out != want {
+ t.Errorf("Major(%q) = %q, want %q", tt.in, out, want)
+ }
+ }
+}
+
+func TestCompare(t *testing.T) {
+ for i, ti := range tests {
+ for j, tj := range tests {
+ cmp := Compare(ti.in, tj.in)
+ var want int
+ if ti.out == tj.out {
+ want = 0
+ } else if i < j {
+ want = -1
+ } else {
+ want = +1
+ }
+ if cmp != want {
+ t.Errorf("Compare(%q, %q) = %d, want %d", ti.in, tj.in, cmp, want)
+ }
+ }
+ }
+}
+
+func TestMax(t *testing.T) {
+ for i, ti := range tests {
+ for j, tj := range tests {
+ max := Max(ti.in, tj.in)
+ want := Canonical(ti.in)
+ if i < j {
+ want = Canonical(tj.in)
+ }
+ if max != want {
+ t.Errorf("Max(%q, %q) = %q, want %q", ti.in, tj.in, max, want)
+ }
+ }
+ }
+}
+
+var (
+ v1 = "v1.0.0+metadata-dash"
+ v2 = "v1.0.0+metadata-dash1"
+)
+
+func BenchmarkCompare(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ if Compare(v1, v2) != 0 {
+ b.Fatalf("bad compare")
+ }
+ }
+}
diff --git a/src/cmd/go/internal/vet/vetflag.go b/src/cmd/go/internal/vet/vetflag.go
index 03770ea920..bdfe033018 100644
--- a/src/cmd/go/internal/vet/vetflag.go
+++ b/src/cmd/go/internal/vet/vetflag.go
@@ -90,7 +90,7 @@ func vetFlags(args []string) (passToVet, packageNames []string) {
}
switch f.Name {
// Flags known to the build but not to vet, so must be dropped.
- case "x", "n", "vettool", "compiler":
+ case "a", "x", "n", "vettool", "compiler":
if extraWord {
args = append(args[:i], args[i+2:]...)
extraWord = false
diff --git a/src/cmd/go/internal/vgo/build.go b/src/cmd/go/internal/vgo/build.go
new file mode 100644
index 0000000000..ba103099aa
--- /dev/null
+++ b/src/cmd/go/internal/vgo/build.go
@@ -0,0 +1,115 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modinfo"
+ "cmd/go/internal/module"
+ "cmd/go/internal/search"
+ "encoding/hex"
+ "fmt"
+ "os"
+ "path/filepath"
+)
+
+var (
+ infoStart, _ = hex.DecodeString("3077af0c9274080241e1c107e6d618e6")
+ infoEnd, _ = hex.DecodeString("f932433186182072008242104116d8f2")
+)
+
+func isStandardImportPath(path string) bool {
+ if search.IsStandardImportPath(path) {
+ if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src", path)); err == nil {
+ return true
+ }
+ if _, err := os.Stat(filepath.Join(cfg.GOROOT, "src/vendor", path)); err == nil {
+ return true
+ }
+ }
+ return false
+}
+
+func PackageModuleInfo(path string) *modinfo.ModulePublic {
+ var info modinfo.ModulePublic
+ if isStandardImportPath(path) || !Enabled() {
+ return nil
+ }
+ target := findModule(path, path)
+ info.Top = target.Path == buildList[0].Path
+ info.Path = target.Path
+ info.Version = target.Version
+ return &info
+}
+
+func PackageBuildInfo(path string, deps []string) string {
+ if isStandardImportPath(path) || !Enabled() {
+ return ""
+ }
+ target := findModule(path, path)
+ mdeps := make(map[module.Version]bool)
+ for _, dep := range deps {
+ if !isStandardImportPath(dep) {
+ mdeps[findModule(path, dep)] = true
+ }
+ }
+ var mods []module.Version
+ delete(mdeps, target)
+ for mod := range mdeps {
+ mods = append(mods, mod)
+ }
+ sortModules(mods)
+
+ var buf bytes.Buffer
+ fmt.Fprintf(&buf, "path\t%s\n", path)
+ tv := target.Version
+ if tv == "" {
+ tv = "(devel)"
+ }
+ fmt.Fprintf(&buf, "mod\t%s\t%s\t%s\n", target.Path, tv, findModHash(target))
+ for _, mod := range mods {
+ mv := mod.Version
+ if mv == "" {
+ mv = "(devel)"
+ }
+ r := replaced(mod)
+ h := ""
+ if r == nil {
+ h = "\t" + findModHash(mod)
+ }
+ fmt.Fprintf(&buf, "dep\t%s\t%s%s\n", mod.Path, mod.Version, h)
+ if r := replaced(mod); r != nil {
+ fmt.Fprintf(&buf, "=>\t%s\t%s\t%s\n", r.New.Path, r.New.Version, findModHash(r.New))
+ }
+ }
+ return buf.String()
+}
+
+func findModule(target, path string) module.Version {
+ if path == "." {
+ return buildList[0]
+ }
+ for _, mod := range buildList {
+ if importPathInModule(path, mod.Path) {
+ return mod
+ }
+ }
+ base.Fatalf("build %v: cannot find module for path %v", target, path)
+ panic("unreachable")
+}
+
+func ModInfoProg(info string) []byte {
+ return []byte(fmt.Sprintf(`
+ package main
+ import _ "unsafe"
+ //go:linkname __debug_modinfo__ runtime/debug.modinfo
+ var __debug_modinfo__ string
+ func init() {
+ __debug_modinfo__ = %q
+ }
+ `, string(infoStart)+info+string(infoEnd)))
+}
diff --git a/src/cmd/go/internal/vgo/fetch.go b/src/cmd/go/internal/vgo/fetch.go
new file mode 100644
index 0000000000..c28353ccfa
--- /dev/null
+++ b/src/cmd/go/internal/vgo/fetch.go
@@ -0,0 +1,232 @@
+// Copyright 2018 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 vgo
+
+import (
+ "archive/zip"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/dirhash"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/module"
+ "cmd/go/internal/semver"
+)
+
+// fetch returns the directory in the local download cache
+// holding the root of mod's source tree.
+// It downloads the module if needed.
+func fetch(mod module.Version) (dir string, err error) {
+ if r := replaced(mod); r != nil {
+ if r.New.Version == "" {
+ dir = r.New.Path
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ModRoot, dir)
+ }
+ return dir, nil
+ }
+ mod = r.New
+ }
+
+ modpath := mod.Path + "@" + mod.Version
+ dir = filepath.Join(srcV, modpath)
+ if files, _ := ioutil.ReadDir(dir); len(files) == 0 {
+ zipfile := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".zip")
+ if _, err := os.Stat(zipfile); err == nil {
+ // Use it.
+ // This should only happen if the v/cache directory is preinitialized
+ // or if src/v/modpath was removed but not src/v/cache.
+ fmt.Fprintf(os.Stderr, "vgo: extracting %s %s\n", mod.Path, mod.Version)
+ } else {
+ if err := os.MkdirAll(filepath.Join(srcV, "cache", mod.Path, "@v"), 0777); err != nil {
+ return "", err
+ }
+ fmt.Fprintf(os.Stderr, "vgo: downloading %s %s\n", mod.Path, mod.Version)
+ if err := downloadZip(mod, zipfile); err != nil {
+ return "", err
+ }
+ }
+ if err := modfetch.Unzip(dir, zipfile, modpath, 0); err != nil {
+ fmt.Fprintf(os.Stderr, "-> %s\n", err)
+ return "", err
+ }
+ }
+ checkModHash(mod)
+ return dir, nil
+}
+
+func downloadZip(mod module.Version, target string) error {
+ repo, err := modfetch.Lookup(mod.Path)
+ if err != nil {
+ return err
+ }
+ tmpfile, err := repo.Zip(mod.Version, os.TempDir())
+ if err != nil {
+ return err
+ }
+ defer os.Remove(tmpfile)
+
+ // Double-check zip file looks OK.
+ z, err := zip.OpenReader(tmpfile)
+ if err != nil {
+ z.Close()
+ return err
+ }
+ prefix := mod.Path + "@" + mod.Version
+ for _, f := range z.File {
+ if !strings.HasPrefix(f.Name, prefix) {
+ z.Close()
+ return fmt.Errorf("zip for %s has unexpected file %s", prefix[:len(prefix)-1], f.Name)
+ }
+ }
+ z.Close()
+
+ hash, err := dirhash.HashZip(tmpfile, dirhash.DefaultHash)
+ if err != nil {
+ return err
+ }
+ r, err := os.Open(tmpfile)
+ if err != nil {
+ return err
+ }
+ defer r.Close()
+ w, err := os.Create(target)
+ if err != nil {
+ return err
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ w.Close()
+ return fmt.Errorf("copying: %v", err)
+ }
+ if err := w.Close(); err != nil {
+ return err
+ }
+ return ioutil.WriteFile(target+"hash", []byte(hash), 0666)
+}
+
+var useModHash = false
+var modHash map[module.Version][]string
+
+func initModHash() {
+ if modHash != nil {
+ return
+ }
+ modHash = make(map[module.Version][]string)
+ file := filepath.Join(ModRoot, "go.modverify")
+ data, err := ioutil.ReadFile(file)
+ if err != nil && os.IsNotExist(err) {
+ return
+ }
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ useModHash = true
+ lineno := 0
+ for len(data) > 0 {
+ var line []byte
+ lineno++
+ i := bytes.IndexByte(data, '\n')
+ if i < 0 {
+ line, data = data, nil
+ } else {
+ line, data = data[:i], data[i+1:]
+ }
+ f := strings.Fields(string(line))
+ if len(f) == 0 {
+ // blank line; skip it
+ continue
+ }
+ if len(f) != 3 {
+ base.Fatalf("vgo: malformed go.modverify:\n%s:%d: wrong number of fields %v", file, lineno, len(f))
+ }
+ mod := module.Version{Path: f[0], Version: f[1]}
+ modHash[mod] = append(modHash[mod], f[2])
+ }
+}
+
+func checkModHash(mod module.Version) {
+ initModHash()
+ if !useModHash {
+ return
+ }
+
+ data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash"))
+ if err != nil {
+ base.Fatalf("vgo: verifying %s %s: %v", mod.Path, mod.Version, err)
+ }
+ h := strings.TrimSpace(string(data))
+ if !strings.HasPrefix(h, "h1:") {
+ base.Fatalf("vgo: verifying %s %s: unexpected ziphash: %q", mod.Path, mod.Version, h)
+ }
+
+ for _, vh := range modHash[mod] {
+ if h == vh {
+ return
+ }
+ if strings.HasPrefix(vh, "h1:") {
+ base.Fatalf("vgo: verifying %s %s: module hash mismatch\n\tdownloaded: %v\n\tgo.modverify: %v", mod.Path, mod.Version, h, vh)
+ }
+ }
+ if len(modHash[mod]) > 0 {
+ fmt.Fprintf(os.Stderr, "warning: verifying %s %s: unknown hashes in go.modverify: %v; adding %v", mod.Path, mod.Version, strings.Join(modHash[mod], ", "), h)
+ }
+ modHash[mod] = append(modHash[mod], h)
+}
+
+func findModHash(mod module.Version) string {
+ data, err := ioutil.ReadFile(filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".ziphash"))
+ if err != nil {
+ return ""
+ }
+ return strings.TrimSpace(string(data))
+}
+
+func writeModHash() {
+ if !useModHash {
+ return
+ }
+
+ var mods []module.Version
+ for m := range modHash {
+ mods = append(mods, m)
+ }
+ sortModules(mods)
+ var buf bytes.Buffer
+ for _, m := range mods {
+ list := modHash[m]
+ sort.Strings(list)
+ for _, h := range list {
+ fmt.Fprintf(&buf, "%s %s %s\n", m.Path, m.Version, h)
+ }
+ }
+
+ file := filepath.Join(ModRoot, "go.modverify")
+ data, _ := ioutil.ReadFile(filepath.Join(ModRoot, "go.modverify"))
+ if bytes.Equal(data, buf.Bytes()) {
+ return
+ }
+
+ if err := ioutil.WriteFile(file, buf.Bytes(), 0666); err != nil {
+ base.Fatalf("vgo: writing go.modverify: %v", err)
+ }
+}
+
+func sortModules(mods []module.Version) {
+ sort.Slice(mods, func(i, j int) bool {
+ mi := mods[i]
+ mj := mods[j]
+ if mi.Path != mj.Path {
+ return mi.Path < mj.Path
+ }
+ return semver.Compare(mi.Version, mj.Version) < 0
+ })
+}
diff --git a/src/cmd/go/internal/vgo/get.go b/src/cmd/go/internal/vgo/get.go
new file mode 100644
index 0000000000..9fd8497f9d
--- /dev/null
+++ b/src/cmd/go/internal/vgo/get.go
@@ -0,0 +1,152 @@
+// Copyright 2018 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 vgo
+
+import (
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/semver"
+)
+
+var CmdGet = &base.Command{
+ UsageLine: "get [build flags] [packages]",
+ Short: "download and install versioned modules and dependencies",
+ Long: `
+Get downloads the latest versions of modules containing the named packages,
+along with the versions of the dependencies required by those modules
+(not necessarily the latest ones).
+
+It then installs the named packages, like 'go install'.
+
+The -u flag causes get to download the latest version of dependencies as well.
+
+Each package being updated can be suffixed with @version to specify
+the desired version. Specifying a version older than the one currently
+in use causes a downgrade, which may in turn downgrade other
+modules using that one, to keep everything consistent.
+
+TODO: Make this documentation better once the semantic dust settles.
+ `,
+}
+
+var getU = CmdGet.Flag.Bool("u", false, "")
+
+func init() {
+ CmdGet.Run = runGet // break init loop
+}
+
+func runGet(cmd *base.Command, args []string) {
+ if *getU && len(args) > 0 {
+ base.Fatalf("vgo get: -u not supported with argument list")
+ }
+ if !*getU && len(args) == 0 {
+ base.Fatalf("vgo get: need arguments or -u")
+ }
+
+ if *getU {
+ isGetU = true
+ ImportPaths([]string{"."})
+ return
+ }
+
+ Init()
+ InitMod()
+ var upgrade []module.Version
+ var downgrade []module.Version
+ var newPkgs []string
+ for _, pkg := range args {
+ var path, vers string
+ /* OLD CODE
+ if n := strings.Count(pkg, "(") + strings.Count(pkg, ")"); n > 0 {
+ i := strings.Index(pkg, "(")
+ j := strings.Index(pkg, ")")
+ if n != 2 || i < 0 || j <= i+1 || j != len(pkg)-1 && pkg[j+1] != '/' {
+ base.Errorf("vgo get: invalid module version syntax: %s", pkg)
+ continue
+ }
+ path, vers = pkg[:i], pkg[i+1:j]
+ pkg = pkg[:i] + pkg[j+1:]
+ */
+ if i := strings.Index(pkg, "@"); i >= 0 {
+ path, pkg, vers = pkg[:i], pkg[:i], pkg[i+1:]
+ if strings.Contains(vers, "@") {
+ base.Errorf("vgo get: invalid module version syntax: %s", pkg)
+ continue
+ }
+ } else {
+ path = pkg
+ vers = "latest"
+ }
+ if vers == "none" {
+ downgrade = append(downgrade, module.Version{Path: path, Version: ""})
+ } else {
+ info, err := modfetch.Query(path, vers, allowed)
+ if err != nil {
+ base.Errorf("vgo get %v: %v", pkg, err)
+ continue
+ }
+ upgrade = append(upgrade, module.Version{Path: path, Version: info.Version})
+ newPkgs = append(newPkgs, pkg)
+ }
+ }
+ args = newPkgs
+
+ // Upgrade.
+ var err error
+ buildList, err = mvs.Upgrade(Target, newReqs(), upgrade...)
+ if err != nil {
+ base.Fatalf("vgo get: %v", err)
+ }
+
+ importPaths([]string{"."})
+
+ // Downgrade anything that went too far.
+ version := make(map[string]string)
+ for _, mod := range buildList {
+ version[mod.Path] = mod.Version
+ }
+ for _, mod := range upgrade {
+ if semver.Compare(mod.Version, version[mod.Path]) < 0 {
+ downgrade = append(downgrade, mod)
+ }
+ }
+
+ if len(downgrade) > 0 {
+ buildList, err = mvs.Downgrade(Target, newReqs(buildList[1:]...), downgrade...)
+ if err != nil {
+ base.Fatalf("vgo get: %v", err)
+ }
+
+ // TODO: Check that everything we need to import is still available.
+ /*
+ local := v.matchPackages("all", v.Reqs[:1])
+ for _, path := range local {
+ dir, err := v.importDir(path)
+ if err != nil {
+ return err // TODO
+ }
+ imports, testImports, err := imports.ScanDir(dir, v.Tags)
+ for _, path := range imports {
+ xxx
+ }
+ for _, path := range testImports {
+ xxx
+ }
+ }
+ */
+ }
+ writeGoMod()
+
+ if len(args) > 0 {
+ InstallHook(args)
+ }
+}
+
+// Call into "go install". Set by internal/work, which imports us.
+var InstallHook func([]string)
diff --git a/src/cmd/go/internal/vgo/init.go b/src/cmd/go/internal/vgo/init.go
new file mode 100644
index 0000000000..b307b6b1fe
--- /dev/null
+++ b/src/cmd/go/internal/vgo/init.go
@@ -0,0 +1,411 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfetch/codehost"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/search"
+ "cmd/go/internal/semver"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path"
+ "path/filepath"
+ "regexp"
+ "strconv"
+ "strings"
+)
+
+var (
+ cwd string
+ enabled = MustBeVgo
+ MustBeVgo = mustBeVgo()
+ initialized bool
+
+ ModRoot string
+ modFile *modfile.File
+ excluded map[module.Version]bool
+ Target module.Version
+
+ gopath string
+ srcV string
+)
+
+func BinDir() string {
+ if !Enabled() {
+ panic("vgo.Bin")
+ }
+ return filepath.Join(gopath, "bin")
+}
+
+func init() {
+ flag.BoolVar(&MustBeVgo, "vgo", MustBeVgo, "require use of modules")
+}
+
+// mustBeVgo reports whether we are invoked as vgo
+// (as opposed to go).
+// If so, we only support builds with go.mod files.
+func mustBeVgo() bool {
+ name := os.Args[0]
+ name = name[strings.LastIndex(name, "/")+1:]
+ name = name[strings.LastIndex(name, `\`)+1:]
+ return strings.HasPrefix(name, "vgo")
+}
+
+func Init() {
+ if initialized {
+ return
+ }
+ initialized = true
+
+ // If this is testgo - the test binary during cmd/go tests - then
+ // do not let it look for a go.mod. Only use vgo support if the
+ // global -vgo flag has been passed on the command line.
+ if base := filepath.Base(os.Args[0]); (base == "testgo" || base == "testgo.exe") && !MustBeVgo {
+ return
+ }
+
+ // Disable any prompting for passwords by Git.
+ // Only has an effect for 2.3.0 or later, but avoiding
+ // the prompt in earlier versions is just too hard.
+ // If user has explicitly set GIT_TERMINAL_PROMPT=1, keep
+ // prompting.
+ // See golang.org/issue/9341 and golang.org/issue/12706.
+ if os.Getenv("GIT_TERMINAL_PROMPT") == "" {
+ os.Setenv("GIT_TERMINAL_PROMPT", "0")
+ }
+
+ // Disable any ssh connection pooling by Git.
+ // If a Git subprocess forks a child into the background to cache a new connection,
+ // that child keeps stdout/stderr open. After the Git subprocess exits,
+ // os /exec expects to be able to read from the stdout/stderr pipe
+ // until EOF to get all the data that the Git subprocess wrote before exiting.
+ // The EOF doesn't come until the child exits too, because the child
+ // is holding the write end of the pipe.
+ // This is unfortunate, but it has come up at least twice
+ // (see golang.org/issue/13453 and golang.org/issue/16104)
+ // and confuses users when it does.
+ // If the user has explicitly set GIT_SSH or GIT_SSH_COMMAND,
+ // assume they know what they are doing and don't step on it.
+ // But default to turning off ControlMaster.
+ if os.Getenv("GIT_SSH") == "" && os.Getenv("GIT_SSH_COMMAND") == "" {
+ os.Setenv("GIT_SSH_COMMAND", "ssh -o ControlMaster=no")
+ }
+
+ var err error
+ cwd, err = os.Getwd()
+ if err != nil {
+ base.Fatalf("go: %v", err)
+ }
+
+ root, _ := FindModuleRoot(cwd, "", MustBeVgo)
+ if root == "" {
+ // If invoked as vgo, insist on a mod file.
+ if MustBeVgo {
+ base.Fatalf("cannot determine module root; please create a go.mod file there")
+ }
+ return
+ }
+ enabled = true
+ ModRoot = root
+ search.SetModRoot(root)
+}
+
+func Enabled() bool {
+ return false // COMPLETELY OFF FOR NOW
+ /*
+ if !initialized {
+ panic("vgo: Enabled called before Init")
+ }
+ return enabled
+ */
+}
+
+func InitMod() {
+ if Init(); !Enabled() || modFile != nil {
+ return
+ }
+
+ list := filepath.SplitList(cfg.BuildContext.GOPATH)
+ if len(list) == 0 || list[0] == "" {
+ base.Fatalf("missing $GOPATH")
+ }
+ gopath = list[0]
+ if _, err := os.Stat(filepath.Join(gopath, "go.mod")); err == nil {
+ base.Fatalf("$GOPATH/go.mod exists but should not")
+ }
+ srcV = filepath.Join(list[0], "src/v")
+ codehost.WorkRoot = filepath.Join(srcV, "cache/vcswork")
+
+ gomod := filepath.Join(ModRoot, "go.mod")
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ legacyModInit()
+ return
+ }
+
+ f, err := modfile.Parse(gomod, data, fixVersion)
+ if err != nil {
+ // Errors returned by modfile.Parse begin with file:line.
+ base.Fatalf("vgo: errors parsing go.mod:\n%s\n", err)
+ }
+ modFile = f
+
+ if len(f.Syntax.Stmt) == 0 || f.Module == nil {
+ // Empty mod file. Must add module path.
+ path, err := FindModulePath(ModRoot)
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ f.AddModuleStmt(path)
+ }
+
+ if len(f.Syntax.Stmt) == 1 && f.Module != nil {
+ // Entire file is just a module statement.
+ // Populate require if possible.
+ legacyModInit()
+ }
+
+ excluded = make(map[module.Version]bool)
+ for _, x := range f.Exclude {
+ excluded[x.Mod] = true
+ }
+ Target = f.Module.Mod
+ writeGoMod()
+}
+
+func allowed(m module.Version) bool {
+ return !excluded[m]
+}
+
+func legacyModInit() {
+ if modFile == nil {
+ path, err := FindModulePath(ModRoot)
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ fmt.Fprintf(os.Stderr, "vgo: creating new go.mod: module %s\n", path)
+ modFile = new(modfile.File)
+ modFile.AddModuleStmt(path)
+ }
+
+ Target = modFile.Module.Mod
+ for _, name := range altConfigs {
+ cfg := filepath.Join(ModRoot, name)
+ data, err := ioutil.ReadFile(cfg)
+ if err == nil {
+ convert := modconv.Converters[name]
+ if convert == nil {
+ return
+ }
+ fmt.Fprintf(os.Stderr, "vgo: copying requirements from %s\n", cfg)
+ cfg = filepath.ToSlash(cfg)
+ if err := modfetch.ConvertLegacyConfig(modFile, cfg, data); err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ if len(modFile.Syntax.Stmt) == 1 {
+ // Add comment to prevent vgo from re-converting every time it runs.
+ modFile.AddComment("// vgo: no requirements found in " + name)
+ }
+ return
+ }
+ }
+}
+
+var altConfigs = []string{
+ "Gopkg.lock",
+
+ "GLOCKFILE",
+ "Godeps/Godeps.json",
+ "dependencies.tsv",
+ "glide.lock",
+ "vendor.conf",
+ "vendor.yml",
+ "vendor/manifest",
+ "vendor/vendor.json",
+
+ ".git/config",
+}
+
+// Exported only for testing.
+func FindModuleRoot(dir, limit string, legacyConfigOK bool) (root, file string) {
+ dir = filepath.Clean(dir)
+ dir1 := dir
+ limit = filepath.Clean(limit)
+
+ // Look for enclosing go.mod.
+ for {
+ if _, err := os.Stat(filepath.Join(dir, "go.mod")); err == nil {
+ return dir, "go.mod"
+ }
+ if dir == limit {
+ break
+ }
+ d := filepath.Dir(dir)
+ if d == dir {
+ break
+ }
+ dir = d
+ }
+
+ // Failing that, look for enclosing alternate version config.
+ if legacyConfigOK {
+ dir = dir1
+ for {
+ for _, name := range altConfigs {
+ if _, err := os.Stat(filepath.Join(dir, name)); err == nil {
+ return dir, name
+ }
+ }
+ if dir == limit {
+ break
+ }
+ d := filepath.Dir(dir)
+ if d == dir {
+ break
+ }
+ dir = d
+ }
+ }
+
+ return "", ""
+}
+
+// Exported only for testing.
+func FindModulePath(dir string) (string, error) {
+ for _, gpdir := range filepath.SplitList(cfg.BuildContext.GOPATH) {
+ src := filepath.Join(gpdir, "src") + string(filepath.Separator)
+ if strings.HasPrefix(dir, src) {
+ return filepath.ToSlash(dir[len(src):]), nil
+ }
+ }
+
+ // Cast about for import comments,
+ // first in top-level directory, then in subdirectories.
+ list, _ := ioutil.ReadDir(dir)
+ for _, info := range list {
+ if info.Mode().IsRegular() && strings.HasSuffix(info.Name(), ".go") {
+ if com := findImportComment(filepath.Join(dir, info.Name())); com != "" {
+ return com, nil
+ }
+ }
+ }
+ for _, info1 := range list {
+ if info1.IsDir() {
+ files, _ := ioutil.ReadDir(filepath.Join(dir, info1.Name()))
+ for _, info2 := range files {
+ if info2.Mode().IsRegular() && strings.HasSuffix(info2.Name(), ".go") {
+ if com := findImportComment(filepath.Join(dir, info1.Name(), info2.Name())); com != "" {
+ return path.Dir(com), nil
+ }
+ }
+ }
+ }
+ }
+
+ // Look for Godeps.json declaring import path.
+ data, _ := ioutil.ReadFile(filepath.Join(dir, "Godeps/Godeps.json"))
+ var cfg struct{ ImportPath string }
+ json.Unmarshal(data, &cfg)
+ if cfg.ImportPath != "" {
+ return cfg.ImportPath, nil
+ }
+
+ // Look for vendor.json declaring import path.
+ data, _ = ioutil.ReadFile(filepath.Join(dir, "vendor/vendor.json"))
+ var cfg2 struct{ RootPath string }
+ json.Unmarshal(data, &cfg2)
+ if cfg2.RootPath != "" {
+ return cfg2.RootPath, nil
+ }
+
+ // Look for .git/config with github origin as last resort.
+ data, _ = ioutil.ReadFile(filepath.Join(dir, ".git/config"))
+ if m := gitOriginRE.FindSubmatch(data); m != nil {
+ return "github.com/" + string(m[1]), nil
+ }
+
+ return "", fmt.Errorf("cannot determine module path for source directory %s (outside GOPATH, no import comments)", dir)
+}
+
+var (
+ gitOriginRE = regexp.MustCompile(`(?m)^\[remote "origin"\]\r?\n\turl = (?:https://github.com/|git@github.com:|gh:)([^/]+/[^/]+?)(\.git)?\r?\n`)
+ importCommentRE = regexp.MustCompile(`(?m)^package[ \t]+[^ \t\r\n/]+[ \t]+//[ \t]+import[ \t]+(\"[^"]+\")[ \t]*\r?\n`)
+)
+
+func findImportComment(file string) string {
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return ""
+ }
+ m := importCommentRE.FindSubmatch(data)
+ if m == nil {
+ return ""
+ }
+ path, err := strconv.Unquote(string(m[1]))
+ if err != nil {
+ return ""
+ }
+ return path
+}
+
+func writeGoMod() {
+ writeModHash()
+
+ if buildList != nil {
+ min, err := mvs.Req(Target, buildList, newReqs())
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ modFile.SetRequire(min)
+ }
+
+ file := filepath.Join(ModRoot, "go.mod")
+ old, _ := ioutil.ReadFile(file)
+ new, err := modFile.Format()
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ if bytes.Equal(old, new) {
+ return
+ }
+ if err := ioutil.WriteFile(file, new, 0666); err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+}
+
+func fixVersion(path, vers string) (string, error) {
+ // Special case: remove the old -gopkgin- hack.
+ if strings.HasPrefix(path, "gopkg.in/") && strings.Contains(vers, "-gopkgin-") {
+ vers = vers[strings.Index(vers, "-gopkgin-")+len("-gopkgin-"):]
+ }
+
+ // fixVersion is called speculatively on every
+ // module, version pair from every go.mod file.
+ // Avoid the query if it looks OK.
+ _, pathMajor, ok := module.SplitPathVersion(path)
+ if !ok {
+ return "", fmt.Errorf("malformed module path: %s", path)
+ }
+ if semver.IsValid(vers) && vers == semver.Canonical(vers) && module.MatchPathMajor(vers, pathMajor) {
+ return vers, nil
+ }
+
+ info, err := modfetch.Query(path, vers, nil)
+ if err != nil {
+ return "", err
+ }
+ return info.Version, nil
+}
diff --git a/src/cmd/go/internal/vgo/list.go b/src/cmd/go/internal/vgo/list.go
new file mode 100644
index 0000000000..c6656c292d
--- /dev/null
+++ b/src/cmd/go/internal/vgo/list.go
@@ -0,0 +1,153 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "os"
+ "regexp"
+ "unicode/utf8"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/module"
+)
+
+func ListT(pkgs []string) {
+ if Init(); !Enabled() {
+ base.Fatalf("go list: cannot use -t outside module")
+ }
+ InitMod()
+
+ if len(pkgs) == 0 {
+ base.Fatalf("vgo list -t: need list of modules")
+ }
+
+ for _, pkg := range pkgs {
+ repo, err := modfetch.Lookup(pkg)
+ if err != nil {
+ base.Errorf("vgo list -t: %v", err)
+ continue
+ }
+ path := repo.ModulePath()
+ fmt.Printf("%s\n", path)
+ tags, err := repo.Versions("")
+ if err != nil {
+ base.Errorf("vgo list -t: %v", err)
+ continue
+ }
+ for _, t := range tags {
+ if excluded[module.Version{Path: path, Version: t}] {
+ t += " # excluded"
+ }
+ fmt.Printf("\t%s\n", t)
+ }
+ }
+}
+
+func ListM() {
+ if Init(); !Enabled() {
+ base.Fatalf("go list: cannot use -m outside module")
+ }
+ InitMod()
+ iterate(func(*loader) {})
+ printListM(os.Stdout)
+}
+
+func printListM(w io.Writer) {
+ var rows [][]string
+ rows = append(rows, []string{"MODULE", "VERSION"})
+ for _, mod := range buildList {
+ v := mod.Version
+ if v == "" {
+ v = "-"
+ }
+ rows = append(rows, []string{mod.Path, v})
+ if r := replaced(mod); r != nil {
+ rows = append(rows, []string{" => " + r.New.Path, r.New.Version})
+ }
+ }
+ printTable(w, rows)
+}
+
+func ListMU() {
+ if Init(); !Enabled() {
+ base.Fatalf("go list: cannot use -m outside module")
+ }
+ InitMod()
+
+ quietLookup = true // do not chatter in v.Lookup
+ iterate(func(*loader) {})
+
+ var rows [][]string
+ rows = append(rows, []string{"MODULE", "VERSION", "LATEST"})
+ for _, mod := range buildList {
+ var latest string
+ v := mod.Version
+ if v == "" {
+ v = "-"
+ latest = "-"
+ } else {
+ info, err := modfetch.Query(mod.Path, "latest", allowed)
+ if err != nil {
+ latest = "ERR: " + err.Error()
+ } else {
+ latest = info.Version
+ if !isPseudoVersion(latest) && !info.Time.IsZero() {
+ latest += info.Time.Local().Format(" (2006-01-02 15:04)")
+ }
+ }
+ if !isPseudoVersion(mod.Version) {
+ if info, err := modfetch.Query(mod.Path, mod.Version, nil); err == nil && !info.Time.IsZero() {
+ v += info.Time.Local().Format(" (2006-01-02 15:04)")
+ }
+ }
+ }
+ if latest == v {
+ latest = "-"
+ }
+ rows = append(rows, []string{mod.Path, v, latest})
+ }
+ printTable(os.Stdout, rows)
+}
+
+var pseudoVersionRE = regexp.MustCompile(`^v[0-9]+\.0\.0-[0-9]{14}-[A-Za-z0-9]+$`)
+
+func isPseudoVersion(v string) bool {
+ return pseudoVersionRE.MatchString(v)
+}
+
+func printTable(w io.Writer, rows [][]string) {
+ var max []int
+ for _, row := range rows {
+ for i, c := range row {
+ n := utf8.RuneCountInString(c)
+ if i >= len(max) {
+ max = append(max, n)
+ } else if max[i] < n {
+ max[i] = n
+ }
+ }
+ }
+
+ b := bufio.NewWriter(w)
+ for _, row := range rows {
+ for len(row) > 0 && row[len(row)-1] == "" {
+ row = row[:len(row)-1]
+ }
+ for i, c := range row {
+ b.WriteString(c)
+ if i+1 < len(row) {
+ for j := utf8.RuneCountInString(c); j < max[i]+2; j++ {
+ b.WriteRune(' ')
+ }
+ }
+ }
+ b.WriteRune('\n')
+ }
+ b.Flush()
+}
diff --git a/src/cmd/go/internal/vgo/load.go b/src/cmd/go/internal/vgo/load.go
new file mode 100644
index 0000000000..3ebba06787
--- /dev/null
+++ b/src/cmd/go/internal/vgo/load.go
@@ -0,0 +1,575 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "go/build"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/modconv"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/modfile"
+ "cmd/go/internal/module"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/search"
+ "cmd/go/internal/semver"
+)
+
+type importLevel int
+
+const (
+ levelNone importLevel = 0
+ levelBuild importLevel = 1
+ levelTest importLevel = 2
+ levelTestRecursive importLevel = 3
+)
+
+var (
+ buildList []module.Version
+ tags map[string]bool
+ importmap map[string]string
+ pkgdir map[string]string
+ pkgmod map[string]module.Version
+ isGetU bool
+)
+
+func AddImports(gofiles []string) {
+ if Init(); !Enabled() {
+ return
+ }
+ InitMod()
+
+ imports, testImports, err := imports.ScanFiles(gofiles, tags)
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+
+ iterate(func(ld *loader) {
+ ld.importList(imports, levelBuild)
+ ld.importList(testImports, levelBuild)
+ })
+ writeGoMod()
+}
+
+func ImportPaths(args []string) []string {
+ if Init(); !Enabled() {
+ return search.ImportPaths(args)
+ }
+ InitMod()
+
+ paths := importPaths(args)
+ writeGoMod()
+ return paths
+}
+
+func importPaths(args []string) []string {
+ level := levelBuild
+ switch cfg.CmdName {
+ case "test", "vet":
+ level = levelTest
+ }
+ cleaned := search.CleanImportPaths(args)
+ iterate(func(ld *loader) {
+ args = expandImportPaths(cleaned)
+ for i, pkg := range args {
+ if pkg == "." || pkg == ".." || strings.HasPrefix(pkg, "./") || strings.HasPrefix(pkg, "../") {
+ dir := filepath.Join(cwd, pkg)
+ if dir == ModRoot {
+ pkg = Target.Path
+ } else if strings.HasPrefix(dir, ModRoot+string(filepath.Separator)) {
+ pkg = Target.Path + filepath.ToSlash(dir[len(ModRoot):])
+ } else {
+ base.Errorf("vgo: package %s outside module root", pkg)
+ continue
+ }
+ args[i] = pkg
+ }
+ ld.importPkg(pkg, level)
+ }
+ })
+ return args
+}
+
+func Lookup(parentPath, path string) (dir, realPath string, err error) {
+ realPath = importmap[path]
+ if realPath == "" {
+ if isStandardImportPath(path) {
+ dir := filepath.Join(cfg.GOROOT, "src", path)
+ if _, err := os.Stat(dir); err == nil {
+ return dir, path, nil
+ }
+ }
+ return "", "", fmt.Errorf("no such package in module")
+ }
+ return pkgdir[realPath], realPath, nil
+}
+
+func iterate(doImports func(*loader)) {
+ var err error
+ mvsOp := mvs.BuildList
+ if isGetU {
+ mvsOp = mvs.UpgradeAll
+ }
+ buildList, err = mvsOp(Target, newReqs())
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+
+ var ld *loader
+ for {
+ ld = newLoader()
+ doImports(ld)
+ if len(ld.missing) == 0 {
+ break
+ }
+ for _, m := range ld.missing {
+ findMissing(m)
+ }
+ base.ExitIfErrors()
+ buildList, err = mvsOp(Target, newReqs())
+ if err != nil {
+ base.Fatalf("vgo: %v", err)
+ }
+ }
+ base.ExitIfErrors()
+
+ importmap = ld.importmap
+ pkgdir = ld.pkgdir
+ pkgmod = ld.pkgmod
+}
+
+type loader struct {
+ imported map[string]importLevel
+ importmap map[string]string
+ pkgdir map[string]string
+ pkgmod map[string]module.Version
+ tags map[string]bool
+ missing []missing
+ imports []string
+ stack []string
+}
+
+type missing struct {
+ path string
+ stack string
+}
+
+func newLoader() *loader {
+ ld := &loader{
+ imported: make(map[string]importLevel),
+ importmap: make(map[string]string),
+ pkgdir: make(map[string]string),
+ pkgmod: make(map[string]module.Version),
+ tags: imports.Tags(),
+ }
+ ld.imported["C"] = 100
+ return ld
+}
+
+func (ld *loader) stackText() string {
+ var buf bytes.Buffer
+ for _, p := range ld.stack[:len(ld.stack)-1] {
+ fmt.Fprintf(&buf, "import %q ->\n\t", p)
+ }
+ fmt.Fprintf(&buf, "import %q", ld.stack[len(ld.stack)-1])
+ return buf.String()
+}
+
+func (ld *loader) importList(pkgs []string, level importLevel) {
+ for _, pkg := range pkgs {
+ ld.importPkg(pkg, level)
+ }
+}
+
+func (ld *loader) importPkg(path string, level importLevel) {
+ if ld.imported[path] >= level {
+ return
+ }
+
+ ld.stack = append(ld.stack, path)
+ defer func() {
+ ld.stack = ld.stack[:len(ld.stack)-1]
+ }()
+
+ // Any rewritings go here.
+ realPath := path
+
+ ld.imported[path] = level
+ ld.importmap[path] = realPath
+ if realPath != path && ld.imported[realPath] >= level {
+ // Already handled.
+ return
+ }
+
+ dir := ld.importDir(realPath)
+ if dir == "" {
+ return
+ }
+
+ ld.pkgdir[realPath] = dir
+
+ imports, testImports, err := imports.ScanDir(dir, ld.tags)
+ if err != nil {
+ base.Errorf("vgo: %s [%s]: %v", ld.stackText(), dir, err)
+ return
+ }
+ nextLevel := level
+ if level == levelTest {
+ nextLevel = levelBuild
+ }
+ for _, pkg := range imports {
+ ld.importPkg(pkg, nextLevel)
+ }
+ if level >= levelTest {
+ for _, pkg := range testImports {
+ ld.importPkg(pkg, nextLevel)
+ }
+ }
+}
+
+func (ld *loader) importDir(path string) string {
+ if importPathInModule(path, Target.Path) {
+ dir := ModRoot
+ if len(path) > len(Target.Path) {
+ dir = filepath.Join(dir, path[len(Target.Path)+1:])
+ }
+ ld.pkgmod[path] = Target
+ return dir
+ }
+
+ i := strings.Index(path, "/")
+ if i < 0 || !strings.Contains(path[:i], ".") {
+ if strings.HasPrefix(path, "golang_org/") {
+ return filepath.Join(cfg.GOROOT, "src/vendor", path)
+ }
+ dir := filepath.Join(cfg.GOROOT, "src", path)
+ if _, err := os.Stat(dir); err == nil {
+ return dir
+ }
+ }
+
+ var mod1 module.Version
+ var dir1 string
+ for _, mod := range buildList {
+ if !importPathInModule(path, mod.Path) {
+ continue
+ }
+ dir, err := fetch(mod)
+ if err != nil {
+ base.Errorf("vgo: %s: %v", ld.stackText(), err)
+ return ""
+ }
+ if len(path) > len(mod.Path) {
+ dir = filepath.Join(dir, path[len(mod.Path)+1:])
+ }
+ if dir1 != "" {
+ base.Errorf("vgo: %s: found in both %v %v and %v %v", ld.stackText(),
+ mod1.Path, mod1.Version, mod.Path, mod.Version)
+ return ""
+ }
+ dir1 = dir
+ mod1 = mod
+ }
+ if dir1 != "" {
+ ld.pkgmod[path] = mod1
+ return dir1
+ }
+ ld.missing = append(ld.missing, missing{path, ld.stackText()})
+ return ""
+}
+
+func replaced(mod module.Version) *modfile.Replace {
+ var found *modfile.Replace
+ for _, r := range modFile.Replace {
+ if r.Old == mod {
+ found = r // keep going
+ }
+ }
+ return found
+}
+
+func importPathInModule(path, mpath string) bool {
+ return mpath == path ||
+ len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath
+}
+
+var found = make(map[string]bool)
+
+func findMissing(m missing) {
+ for _, mod := range buildList {
+ if importPathInModule(m.path, mod.Path) {
+ // Leave for ordinary build to complain about the missing import.
+ return
+ }
+ }
+ if build.IsLocalImport(m.path) {
+ base.Errorf("vgo: relative import is not supported: %s", m.path)
+ return
+ }
+ fmt.Fprintf(os.Stderr, "vgo: resolving import %q\n", m.path)
+ repo, info, err := modfetch.Import(m.path, allowed)
+ if err != nil {
+ base.Errorf("vgo: %s: %v", m.stack, err)
+ return
+ }
+ root := repo.ModulePath()
+ fmt.Fprintf(os.Stderr, "vgo: finding %s (latest)\n", root)
+ if found[root] {
+ base.Fatalf("internal error: findmissing loop on %s", root)
+ }
+ found[root] = true
+ fmt.Fprintf(os.Stderr, "vgo: adding %s %s\n", root, info.Version)
+ buildList = append(buildList, module.Version{Path: root, Version: info.Version})
+ modFile.AddRequire(root, info.Version)
+}
+
+type mvsReqs struct {
+ extra []module.Version
+}
+
+func newReqs(extra ...module.Version) *mvsReqs {
+ r := &mvsReqs{
+ extra: extra,
+ }
+ return r
+}
+
+func (r *mvsReqs) Required(mod module.Version) ([]module.Version, error) {
+ list, err := r.required(mod)
+ if err != nil {
+ return nil, err
+ }
+ if *getU {
+ for i := range list {
+ list[i].Version = "none"
+ }
+ return list, nil
+ }
+ for i, mv := range list {
+ for excluded[mv] {
+ mv1, err := r.Next(mv)
+ if err != nil {
+ return nil, err
+ }
+ if mv1.Version == "" {
+ return nil, fmt.Errorf("%s(%s) depends on excluded %s(%s) with no newer version available", mod.Path, mod.Version, mv.Path, mv.Version)
+ }
+ mv = mv1
+ }
+ list[i] = mv
+ }
+ return list, nil
+}
+
+var vgoVersion = []byte(modconv.Prefix)
+
+func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
+ if mod == Target {
+ var list []module.Version
+ if buildList != nil {
+ list = append(list, buildList[1:]...)
+ return list, nil
+ }
+ for _, r := range modFile.Require {
+ list = append(list, r.Mod)
+ }
+ list = append(list, r.extra...)
+ return list, nil
+ }
+
+ origPath := mod.Path
+ if repl := replaced(mod); repl != nil {
+ if repl.New.Version == "" {
+ // TODO: need to slip the new version into the tags list etc.
+ dir := repl.New.Path
+ if !filepath.IsAbs(dir) {
+ dir = filepath.Join(ModRoot, dir)
+ }
+ gomod := filepath.Join(dir, "go.mod")
+ data, err := ioutil.ReadFile(gomod)
+ if err != nil {
+ return nil, err
+ }
+ f, err := modfile.Parse(gomod, data, nil)
+ if err != nil {
+ return nil, err
+ }
+ var list []module.Version
+ for _, r := range f.Require {
+ list = append(list, r.Mod)
+ }
+ return list, nil
+ }
+ mod = repl.New
+ }
+
+ if mod.Version == "none" {
+ return nil, nil
+ }
+
+ if !semver.IsValid(mod.Version) {
+ // Disallow the broader queries supported by fetch.Lookup.
+ panic(fmt.Errorf("invalid semantic version %q for %s", mod.Version, mod.Path))
+ // TODO return nil, fmt.Errorf("invalid semantic version %q", mod.Version)
+ }
+
+ gomod := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".mod")
+ infofile := filepath.Join(srcV, "cache", mod.Path, "@v", mod.Version+".info")
+ var f *modfile.File
+ if data, err := ioutil.ReadFile(gomod); err == nil {
+ // If go.mod has a //vgo comment at the start,
+ // it was auto-converted from a legacy lock file.
+ // The auto-conversion details may have bugs and
+ // may be fixed in newer versions of vgo.
+ // We ignore cached go.mod files if they do not match
+ // our own vgoVersion.
+ if !bytes.HasPrefix(data, vgoVersion[:len("//vgo")]) || bytes.HasPrefix(data, vgoVersion) {
+ f, err := modfile.Parse(gomod, data, nil)
+ if err != nil {
+ return nil, err
+ }
+ var list []module.Version
+ for _, r := range f.Require {
+ list = append(list, r.Mod)
+ }
+ return list, nil
+ }
+ f, err = modfile.Parse("go.mod", data, nil)
+ if err != nil {
+ return nil, fmt.Errorf("parsing downloaded go.mod: %v", err)
+ }
+ } else {
+ if !quietLookup {
+ fmt.Fprintf(os.Stderr, "vgo: finding %s %s\n", mod.Path, mod.Version)
+ }
+ repo, err := modfetch.Lookup(mod.Path)
+ if err != nil {
+ base.Errorf("vgo: %s: %v\n", mod.Path, err)
+ return nil, err
+ }
+ info, err := repo.Stat(mod.Version)
+ if err != nil {
+ base.Errorf("vgo: %s %s: %v\n", mod.Path, mod.Version, err)
+ return nil, err
+ }
+ data, err := repo.GoMod(info.Version)
+ if err != nil {
+ base.Errorf("vgo: %s %s: %v\n", mod.Path, mod.Version, err)
+ return nil, err
+ }
+
+ f, err = modfile.Parse("go.mod", data, nil)
+ if err != nil {
+ return nil, fmt.Errorf("parsing downloaded go.mod: %v", err)
+ }
+
+ dir := filepath.Dir(gomod)
+ if err := os.MkdirAll(dir, 0777); err != nil {
+ return nil, fmt.Errorf("caching go.mod: %v", err)
+ }
+ js, err := json.Marshal(info)
+ if err != nil {
+ return nil, fmt.Errorf("internal error: json failure: %v", err)
+ }
+ if err := ioutil.WriteFile(infofile, js, 0666); err != nil {
+ return nil, fmt.Errorf("caching info: %v", err)
+ }
+ if err := ioutil.WriteFile(gomod, data, 0666); err != nil {
+ return nil, fmt.Errorf("caching go.mod: %v", err)
+ }
+ }
+ if mpath := f.Module.Mod.Path; mpath != origPath && mpath != mod.Path {
+ return nil, fmt.Errorf("downloaded %q and got module %q", mod.Path, mpath)
+ }
+
+ var list []module.Version
+ for _, req := range f.Require {
+ list = append(list, req.Mod)
+ }
+ if false {
+ fmt.Fprintf(os.Stderr, "REQLIST %v:\n", mod)
+ for _, req := range list {
+ fmt.Fprintf(os.Stderr, "\t%v\n", req)
+ }
+ }
+ return list, nil
+}
+
+var quietLookup bool
+
+func (*mvsReqs) Max(v1, v2 string) string {
+ if semver.Compare(v1, v2) == -1 {
+ return v2
+ }
+ return v1
+}
+
+func (*mvsReqs) Latest(path string) (module.Version, error) {
+ // Note that query "latest" is not the same as
+ // using repo.Latest.
+ // The query only falls back to untagged versions
+ // if nothing is tagged. The Latest method
+ // only ever returns untagged versions,
+ // which is not what we want.
+ fmt.Fprintf(os.Stderr, "vgo: finding %s latest\n", path)
+ info, err := modfetch.Query(path, "latest", allowed)
+ if err != nil {
+ return module.Version{}, err
+ }
+ return module.Version{Path: path, Version: info.Version}, nil
+}
+
+var versionCache = make(map[string][]string)
+
+func versions(path string) ([]string, error) {
+ list, ok := versionCache[path]
+ if !ok {
+ var err error
+ repo, err := modfetch.Lookup(path)
+ if err != nil {
+ return nil, err
+ }
+ list, err = repo.Versions("")
+ if err != nil {
+ return nil, err
+ }
+ versionCache[path] = list
+ }
+ return list, nil
+}
+
+func (*mvsReqs) Previous(m module.Version) (module.Version, error) {
+ list, err := versions(m.Path)
+ if err != nil {
+ return module.Version{}, err
+ }
+ i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) >= 0 })
+ if i > 0 {
+ return module.Version{Path: m.Path, Version: list[i-1]}, nil
+ }
+ return module.Version{Path: m.Path, Version: "none"}, nil
+}
+
+func (*mvsReqs) Next(m module.Version) (module.Version, error) {
+ list, err := versions(m.Path)
+ if err != nil {
+ return module.Version{}, err
+ }
+ i := sort.Search(len(list), func(i int) bool { return semver.Compare(list[i], m.Version) > 0 })
+ if i < len(list) {
+ return module.Version{Path: m.Path, Version: list[i]}, nil
+ }
+ return module.Version{Path: m.Path, Version: "none"}, nil
+}
diff --git a/src/cmd/go/internal/vgo/search.go b/src/cmd/go/internal/vgo/search.go
new file mode 100644
index 0000000000..c3f7ab13bf
--- /dev/null
+++ b/src/cmd/go/internal/vgo/search.go
@@ -0,0 +1,196 @@
+// Copyright 2018 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 vgo
+
+import (
+ "fmt"
+ "go/build"
+ "os"
+ "path/filepath"
+ "sort"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/module"
+ "cmd/go/internal/search"
+)
+
+func expandImportPaths(args []string) []string {
+ var out []string
+ for _, a := range args {
+ // TODO(rsc): Move a == "ALL" test into search.IsMetaPackage
+ // once we officially lock in all the module work (tentatively, Go 1.12).
+ if search.IsMetaPackage(a) || a == "ALL" {
+ switch a {
+ default:
+ fmt.Fprintf(os.Stderr, "vgo: warning: %q matches no packages when using modules\n", a)
+ case "all", "ALL":
+ out = append(out, AllPackages(a)...)
+ }
+ continue
+ }
+ if strings.Contains(a, "...") {
+ if build.IsLocalImport(a) {
+ out = append(out, search.AllPackagesInFS(a)...)
+ } else {
+ out = append(out, AllPackages(a)...)
+ }
+ continue
+ }
+ out = append(out, a)
+ }
+ return out
+}
+
+// AllPackages returns all the packages that can be found
+// under the $GOPATH directories and $GOROOT matching pattern.
+// The pattern is either "all" (all packages), "std" (standard packages),
+// "cmd" (standard commands), or a path including "...".
+func AllPackages(pattern string) []string {
+ pkgs := MatchPackages(pattern)
+ if len(pkgs) == 0 {
+ fmt.Fprintf(os.Stderr, "warning: %q matched no packages\n", pattern)
+ }
+ return pkgs
+}
+
+// MatchPackages returns a list of package paths matching pattern
+// (see go help packages for pattern syntax).
+func MatchPackages(pattern string) []string {
+ if pattern == "std" || pattern == "cmd" {
+ return nil
+ }
+ if pattern == "all" {
+ return MatchAll()
+ }
+ if pattern == "ALL" {
+ return MatchALL()
+ }
+
+ return matchPackages(pattern, buildList)
+}
+
+func matchPackages(pattern string, buildList []module.Version) []string {
+ match := func(string) bool { return true }
+ treeCanMatch := func(string) bool { return true }
+ if !search.IsMetaPackage(pattern) && pattern != "ALL" {
+ match = search.MatchPattern(pattern)
+ treeCanMatch = search.TreeCanMatchPattern(pattern)
+ }
+
+ have := map[string]bool{
+ "builtin": true, // ignore pseudo-package that exists only for documentation
+ }
+ if !cfg.BuildContext.CgoEnabled {
+ have["runtime/cgo"] = true // ignore during walk
+ }
+ var pkgs []string
+
+ for _, mod := range buildList {
+ if !treeCanMatch(mod.Path) {
+ continue
+ }
+ var root string
+ if mod.Version == "" {
+ root = ModRoot
+ } else {
+ var err error
+ root, err = fetch(mod)
+ if err != nil {
+ base.Errorf("vgo: %v", err)
+ continue
+ }
+ }
+ root = filepath.Clean(root)
+
+ filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return nil
+ }
+
+ want := true
+ // Avoid .foo, _foo, and testdata directory trees.
+ _, elem := filepath.Split(path)
+ if strings.HasPrefix(elem, ".") || strings.HasPrefix(elem, "_") || elem == "testdata" {
+ want = false
+ }
+
+ name := mod.Path + filepath.ToSlash(path[len(root):])
+ if !treeCanMatch(name) {
+ want = false
+ }
+
+ if !fi.IsDir() {
+ if fi.Mode()&os.ModeSymlink != 0 && want {
+ if target, err := os.Stat(path); err == nil && target.IsDir() {
+ fmt.Fprintf(os.Stderr, "warning: ignoring symlink %s\n", path)
+ }
+ }
+ return nil
+ }
+
+ if !want {
+ return filepath.SkipDir
+ }
+ if path != root {
+ if _, err := os.Stat(filepath.Join(path, "go.mod")); err == nil {
+ return filepath.SkipDir
+ }
+ }
+
+ if !have[name] {
+ have[name] = true
+ if match(name) {
+ if _, _, err := imports.ScanDir(path, imports.Tags()); err != imports.ErrNoGo {
+ pkgs = append(pkgs, name)
+ }
+ }
+ }
+
+ if elem == "vendor" {
+ return filepath.SkipDir
+ }
+ return nil
+ })
+ }
+ return pkgs
+}
+
+// MatchAll returns a list of the packages matching the pattern "all".
+// We redefine "all" to mean start with the packages in the current module
+// and then follow imports into other modules to add packages imported
+// (directly or indirectly) as part of builds in this module.
+// It does not include packages in other modules that are not needed
+// by builds of this module.
+func MatchAll() []string {
+ return matchAll(imports.Tags())
+}
+
+// MatchALL returns a list of the packages matching the pattern "ALL".
+// The pattern "ALL" is like "all" but looks at all source files,
+// even ones that would be ignored by current build tag settings.
+// That's useful for identifying which packages to include in a vendor directory.
+func MatchALL() []string {
+ return matchAll(map[string]bool{"*": true})
+}
+
+// matchAll is the common implementation of MatchAll and MatchALL,
+// which differ only in the set of tags to apply to select files.
+func matchAll(tags map[string]bool) []string {
+ local := matchPackages("all", buildList[:1])
+ ld := newLoader()
+ ld.tags = tags
+ ld.importList(local, levelTestRecursive)
+ var all []string
+ for _, pkg := range ld.importmap {
+ if !isStandardImportPath(pkg) {
+ all = append(all, pkg)
+ }
+ }
+ sort.Strings(all)
+ return all
+}
diff --git a/src/cmd/go/internal/vgo/vendor.go b/src/cmd/go/internal/vgo/vendor.go
new file mode 100644
index 0000000000..acba4afbbc
--- /dev/null
+++ b/src/cmd/go/internal/vgo/vendor.go
@@ -0,0 +1,156 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "strings"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/module"
+)
+
+var CmdVendor = &base.Command{
+ UsageLine: "vendor [-v]",
+ Short: "vendor dependencies of current module",
+ Long: `
+Vendor resets the module's vendor directory to include all
+packages needed to build and test all packages in the module
+and their dependencies.
+
+The -v flag causes vendor to print to standard error the
+module paths of the modules processed and the import paths
+of the packages copied.
+ `,
+}
+
+var vendorV = CmdVendor.Flag.Bool("v", false, "")
+
+func init() {
+ CmdVendor.Run = runVendor // break init cycle
+}
+
+func runVendor(cmd *base.Command, args []string) {
+ if Init(); !Enabled() {
+ base.Fatalf("vgo vendor: cannot use -m outside module")
+ }
+ if len(args) != 0 {
+ base.Fatalf("vgo vendor: vendor takes no arguments")
+ }
+ InitMod()
+ pkgs := ImportPaths([]string{"ALL"})
+
+ vdir := filepath.Join(ModRoot, "vendor")
+ if err := os.RemoveAll(vdir); err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+
+ modpkgs := make(map[module.Version][]string)
+ for _, pkg := range pkgs {
+ m := pkgmod[pkg]
+ if m == Target {
+ continue
+ }
+ modpkgs[m] = append(modpkgs[m], pkg)
+ }
+
+ var buf bytes.Buffer
+ for _, m := range buildList[1:] {
+ if pkgs := modpkgs[m]; len(pkgs) > 0 {
+ repl := ""
+ if r := replaced(m); r != nil {
+ repl = " => " + r.New.Path
+ if r.New.Version != "" {
+ repl += " " + r.New.Version
+ }
+ }
+ fmt.Fprintf(&buf, "# %s %s%s\n", m.Path, m.Version, repl)
+ if *vendorV {
+ fmt.Fprintf(os.Stderr, "# %s %s%s\n", m.Path, m.Version, repl)
+ }
+ for _, pkg := range pkgs {
+ fmt.Fprintf(&buf, "%s\n", pkg)
+ if *vendorV {
+ fmt.Fprintf(os.Stderr, "%s\n", pkg)
+ }
+ vendorPkg(vdir, pkg)
+ }
+ }
+ }
+ if err := ioutil.WriteFile(filepath.Join(vdir, "vgo.list"), buf.Bytes(), 0666); err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+}
+
+func vendorPkg(vdir, pkg string) {
+ realPath := importmap[pkg]
+ if realPath != pkg && importmap[realPath] != "" {
+ fmt.Fprintf(os.Stderr, "warning: %s imported as both %s and %s; making two copies.\n", realPath, realPath, pkg)
+ }
+
+ dst := filepath.Join(vdir, pkg)
+ src := pkgdir[realPath]
+ if src == "" {
+ fmt.Fprintf(os.Stderr, "internal error: no pkg for %s -> %s\n", pkg, realPath)
+ }
+ copyDir(dst, src, false)
+}
+
+func copyDir(dst, src string, recursive bool) {
+ files, err := ioutil.ReadDir(src)
+ if err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ if err := os.MkdirAll(dst, 0777); err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ for _, file := range files {
+ if file.IsDir() {
+ if recursive || file.Name() == "testdata" {
+ copyDir(filepath.Join(dst, file.Name()), filepath.Join(src, file.Name()), true)
+ }
+ continue
+ }
+ if !file.Mode().IsRegular() {
+ continue
+ }
+ r, err := os.Open(filepath.Join(src, file.Name()))
+ if err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ w, err := os.Create(filepath.Join(dst, file.Name()))
+ if err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ if _, err := io.Copy(w, r); err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ r.Close()
+ if err := w.Close(); err != nil {
+ base.Fatalf("vgo vendor: %v", err)
+ }
+ }
+}
+
+// hasPathPrefix reports whether the path s begins with the
+// elements in prefix.
+func hasPathPrefix(s, prefix string) bool {
+ switch {
+ default:
+ return false
+ case len(s) == len(prefix):
+ return s == prefix
+ case len(s) > len(prefix):
+ if prefix != "" && prefix[len(prefix)-1] == '/' {
+ return strings.HasPrefix(s, prefix)
+ }
+ return s[len(prefix)] == '/' && s[:len(prefix)] == prefix
+ }
+}
diff --git a/src/cmd/go/internal/vgo/verify.go b/src/cmd/go/internal/vgo/verify.go
new file mode 100644
index 0000000000..d21c9d7673
--- /dev/null
+++ b/src/cmd/go/internal/vgo/verify.go
@@ -0,0 +1,104 @@
+// Copyright 2018 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 vgo
+
+import (
+ "bytes"
+ "fmt"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+
+ "cmd/go/internal/base"
+ "cmd/go/internal/dirhash"
+ "cmd/go/internal/module"
+)
+
+var CmdVerify = &base.Command{
+ UsageLine: "verify",
+ Run: runVerify,
+ Short: "verify downloaded modules against expected hashes",
+ Long: `
+Verify checks that the dependencies of the current module,
+which are stored in a local downloaded source cache,
+have not been modified since being downloaded.
+
+If all the modules are unmodified, verify prints
+
+ all modules verified
+
+and exits successfully (status 0). Otherwise, verify reports
+which modules have been changed and exits with a non-zero status.
+ `,
+}
+
+func runVerify(cmd *base.Command, args []string) {
+ if Init(); !Enabled() {
+ base.Fatalf("vgo verify: cannot use outside module")
+ }
+ if len(args) != 0 {
+ // TODO: take arguments
+ base.Fatalf("vgo verify: verify takes no arguments")
+ }
+
+ // Make go.mod consistent but don't load any packages.
+ InitMod()
+ iterate(func(*loader) {})
+ writeGoMod()
+
+ ok := true
+ for _, mod := range buildList[1:] {
+ ok = verifyMod(mod) && ok
+ }
+ if ok {
+ fmt.Printf("all modules verified\n")
+ }
+}
+
+func verifyMod(mod module.Version) bool {
+ ok := true
+ zip := filepath.Join(srcV, "cache", mod.Path, "/@v/", mod.Version+".zip")
+ _, zipErr := os.Stat(zip)
+ dir := filepath.Join(srcV, mod.Path+"@"+mod.Version)
+ _, dirErr := os.Stat(dir)
+ data, err := ioutil.ReadFile(zip + "hash")
+ if err != nil {
+ if zipErr != nil && os.IsNotExist(zipErr) && dirErr != nil && os.IsNotExist(dirErr) {
+ // Nothing downloaded yet. Nothing to verify.
+ return true
+ }
+ base.Errorf("%s %s: missing ziphash: %v", mod.Path, mod.Version, err)
+ return false
+ }
+ h := string(bytes.TrimSpace(data))
+
+ if zipErr != nil && os.IsNotExist(zipErr) {
+ // ok
+ } else {
+ hZ, err := dirhash.HashZip(zip, dirhash.DefaultHash)
+ if err != nil {
+ base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
+ return false
+ } else if hZ != h {
+ base.Errorf("%s %s: zip has been modified (%v)", mod.Path, mod.Version, zip)
+ ok = false
+ }
+ }
+ if dirErr != nil && os.IsNotExist(dirErr) {
+ // ok
+ } else {
+ hD, err := dirhash.HashDir(dir, mod.Path+"@"+mod.Version, dirhash.DefaultHash)
+ if err != nil {
+
+ base.Errorf("%s %s: %v", mod.Path, mod.Version, err)
+ return false
+ }
+ if hD != h {
+ base.Errorf("%s %s: dir has been modified (%v)", mod.Path, mod.Version, dir)
+ ok = false
+ }
+ }
+ return ok
+}
diff --git a/src/cmd/go/internal/web2/web.go b/src/cmd/go/internal/web2/web.go
new file mode 100644
index 0000000000..d11ee6bb2b
--- /dev/null
+++ b/src/cmd/go/internal/web2/web.go
@@ -0,0 +1,297 @@
+// Copyright 2018 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 web2
+
+import (
+ "bytes"
+ "cmd/go/internal/base"
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "net/http"
+ "os"
+ "path/filepath"
+ "runtime"
+ "runtime/debug"
+ "strings"
+ "sync"
+)
+
+var TraceGET = false
+var webstack = false
+
+func init() {
+ flag.BoolVar(&TraceGET, "webtrace", TraceGET, "trace GET requests")
+ flag.BoolVar(&webstack, "webstack", webstack, "print stack for GET requests")
+}
+
+type netrcLine struct {
+ machine string
+ login string
+ password string
+}
+
+var netrcOnce sync.Once
+var netrc []netrcLine
+
+func parseNetrc(data string) []netrcLine {
+ var nrc []netrcLine
+ var l netrcLine
+ for _, line := range strings.Split(data, "\n") {
+ f := strings.Fields(line)
+ for i := 0; i < len(f)-1; i += 2 {
+ switch f[i] {
+ case "machine":
+ l.machine = f[i+1]
+ case "login":
+ l.login = f[i+1]
+ case "password":
+ l.password = f[i+1]
+ }
+ }
+ if l.machine != "" && l.login != "" && l.password != "" {
+ nrc = append(nrc, l)
+ l = netrcLine{}
+ }
+ }
+ return nrc
+}
+
+func havePassword(machine string) bool {
+ netrcOnce.Do(readNetrc)
+ for _, line := range netrc {
+ if line.machine == machine {
+ return true
+ }
+ }
+ return false
+}
+
+func netrcPath() string {
+ switch runtime.GOOS {
+ case "windows":
+ return filepath.Join(os.Getenv("USERPROFILE"), "_netrc")
+ case "plan9":
+ return filepath.Join(os.Getenv("home"), ".netrc")
+ default:
+ return filepath.Join(os.Getenv("HOME"), ".netrc")
+ }
+}
+
+func readNetrc() {
+ data, err := ioutil.ReadFile(netrcPath())
+ if err != nil {
+ return
+ }
+ netrc = parseNetrc(string(data))
+}
+
+type getState struct {
+ req *http.Request
+ resp *http.Response
+ body io.ReadCloser
+ non200ok bool
+}
+
+type Option interface {
+ option(*getState) error
+}
+
+func Non200OK() Option {
+ return optionFunc(func(g *getState) error {
+ g.non200ok = true
+ return nil
+ })
+}
+
+type optionFunc func(*getState) error
+
+func (f optionFunc) option(g *getState) error {
+ return f(g)
+}
+
+func DecodeJSON(dst interface{}) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ return json.NewDecoder(g.body).Decode(dst)
+ }
+ return nil
+ })
+}
+
+func ReadAllBody(body *[]byte) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ var err error
+ *body, err = ioutil.ReadAll(g.body)
+ return err
+ }
+ return nil
+ })
+}
+
+func Body(body *io.ReadCloser) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *body = g.body
+ g.body = nil
+ }
+ return nil
+ })
+}
+
+func Header(hdr *http.Header) Option {
+ return optionFunc(func(g *getState) error {
+ if g.resp != nil {
+ *hdr = CopyHeader(g.resp.Header)
+ }
+ return nil
+ })
+}
+
+func CopyHeader(hdr http.Header) http.Header {
+ if hdr == nil {
+ return nil
+ }
+ h2 := make(http.Header)
+ for k, v := range hdr {
+ v2 := make([]string, len(v))
+ copy(v2, v)
+ h2[k] = v2
+ }
+ return h2
+}
+
+var cache struct {
+ mu sync.Mutex
+ byURL map[string]*cacheEntry
+}
+
+type cacheEntry struct {
+ mu sync.Mutex
+ resp *http.Response
+ body []byte
+}
+
+var httpDo = http.DefaultClient.Do
+
+func SetHTTPDoForTesting(do func(*http.Request) (*http.Response, error)) {
+ if do == nil {
+ do = http.DefaultClient.Do
+ }
+ httpDo = do
+}
+
+func Get(url string, options ...Option) error {
+ if TraceGET || webstack {
+ println("GET", url)
+ if webstack {
+ println(string(debug.Stack()))
+ }
+ }
+
+ req, err := http.NewRequest("GET", url, nil)
+ if err != nil {
+ return err
+ }
+
+ netrcOnce.Do(readNetrc)
+ for _, l := range netrc {
+ if l.machine == req.URL.Host {
+ req.SetBasicAuth(l.login, l.password)
+ break
+ }
+ }
+
+ g := &getState{req: req}
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+
+ cache.mu.Lock()
+ e := cache.byURL[url]
+ if e == nil {
+ e = new(cacheEntry)
+ if !strings.HasPrefix(url, "file:") {
+ if cache.byURL == nil {
+ cache.byURL = make(map[string]*cacheEntry)
+ }
+ cache.byURL[url] = e
+ }
+ }
+ cache.mu.Unlock()
+
+ e.mu.Lock()
+ if strings.HasPrefix(url, "file:") {
+ body, err := ioutil.ReadFile(req.URL.Path)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ e.resp = &http.Response{
+ StatusCode: 200,
+ }
+ } else if e.resp == nil {
+ resp, err := httpDo(req)
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.resp = resp
+ // TODO: Spool to temp file.
+ body, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ resp.Body = nil
+ if err != nil {
+ e.mu.Unlock()
+ return err
+ }
+ e.body = body
+ }
+ g.resp = e.resp
+ g.body = ioutil.NopCloser(bytes.NewReader(e.body))
+ e.mu.Unlock()
+
+ defer func() {
+ if g.body != nil {
+ g.body.Close()
+ }
+ }()
+
+ if g.resp.StatusCode == 403 && req.URL.Host == "api.github.com" && !havePassword("api.github.com") {
+ base.Errorf("%s", githubMessage)
+ }
+ if !g.non200ok && g.resp.StatusCode != 200 {
+ return fmt.Errorf("unexpected status (%s): %v", url, g.resp.Status)
+ }
+
+ for _, o := range options {
+ if err := o.option(g); err != nil {
+ return err
+ }
+ }
+ return err
+}
+
+var githubMessage = `vgo: 403 response from api.github.com
+
+GitHub applies fairly small rate limits to unauthenticated users, and
+you appear to be hitting them. To authenticate, please visit
+https://github.com/settings/tokens and click "Generate New Token" to
+create a Personal Access Token. The token only needs "public_repo"
+scope, but you can add "repo" if you want to access private
+repositories too.
+
+Add the token to your $HOME/.netrc (%USERPROFILE%\_netrc on Windows):
+
+ machine api.github.com login YOU password TOKEN
+
+Sorry for the interruption.
+`
diff --git a/src/cmd/go/internal/web2/web_test.go b/src/cmd/go/internal/web2/web_test.go
new file mode 100644
index 0000000000..c6f6b1eff4
--- /dev/null
+++ b/src/cmd/go/internal/web2/web_test.go
@@ -0,0 +1,35 @@
+// Copyright 2018 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 web2
+
+import (
+ "reflect"
+ "testing"
+)
+
+var testNetrc = `
+machine api.github.com
+ login user
+ password pwd
+
+machine incomlete.host
+ login justlogin
+
+machine test.host
+login user2
+password pwd2
+`
+
+func TestReadNetrc(t *testing.T) {
+ lines := parseNetrc(testNetrc)
+ want := []netrcLine{
+ {"api.github.com", "user", "pwd"},
+ {"test.host", "user2", "pwd2"},
+ }
+
+ if !reflect.DeepEqual(lines, want) {
+ t.Errorf("parseNetrc:\nhave %q\nwant %q", lines, want)
+ }
+}
diff --git a/src/cmd/go/internal/webtest/test.go b/src/cmd/go/internal/webtest/test.go
new file mode 100644
index 0000000000..94b20a33ff
--- /dev/null
+++ b/src/cmd/go/internal/webtest/test.go
@@ -0,0 +1,314 @@
+// Copyright 2018 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 webtest
+
+import (
+ "bufio"
+ "bytes"
+ "encoding/hex"
+ "flag"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "os"
+ "sort"
+ "strconv"
+ "strings"
+ "sync"
+ "unicode/utf8"
+
+ web "cmd/go/internal/web2"
+)
+
+var mode = flag.String("webtest", "replay", "set webtest `mode` - record, replay, bypass")
+
+func Hook() {
+ if *mode == "bypass" {
+ return
+ }
+ web.SetHTTPDoForTesting(Do)
+}
+
+func Unhook() {
+ web.SetHTTPDoForTesting(nil)
+}
+
+func Print() {
+ web.SetHTTPDoForTesting(DoPrint)
+}
+
+var responses struct {
+ mu sync.Mutex
+ byURL map[string]*respEntry
+}
+
+type respEntry struct {
+ status string
+ code int
+ hdr http.Header
+ body []byte
+}
+
+func Serve(url string, status string, hdr http.Header, body []byte) {
+ if status == "" {
+ status = "200 OK"
+ }
+ code, err := strconv.Atoi(strings.Fields(status)[0])
+ if err != nil {
+ panic("bad Serve status - " + status + " - " + err.Error())
+ }
+
+ responses.mu.Lock()
+ defer responses.mu.Unlock()
+
+ if responses.byURL == nil {
+ responses.byURL = make(map[string]*respEntry)
+ }
+ responses.byURL[url] = &respEntry{status: status, code: code, hdr: web.CopyHeader(hdr), body: body}
+}
+
+func Do(req *http.Request) (*http.Response, error) {
+ if req.Method != "GET" {
+ return nil, fmt.Errorf("bad method - must be GET")
+ }
+
+ responses.mu.Lock()
+ e := responses.byURL[req.URL.String()]
+ responses.mu.Unlock()
+
+ if e == nil {
+ if *mode == "record" {
+ loaded.mu.Lock()
+ if len(loaded.did) != 1 {
+ loaded.mu.Unlock()
+ return nil, fmt.Errorf("cannot use -webtest=record with multiple loaded response files")
+ }
+ var file string
+ for file = range loaded.did {
+ break
+ }
+ loaded.mu.Unlock()
+ return doSave(file, req)
+ }
+ e = &respEntry{code: 599, status: "599 unexpected request (no canned response)"}
+ }
+ resp := &http.Response{
+ Status: e.status,
+ StatusCode: e.code,
+ Header: web.CopyHeader(e.hdr),
+ Body: ioutil.NopCloser(bytes.NewReader(e.body)),
+ }
+ return resp, nil
+}
+
+func DoPrint(req *http.Request) (*http.Response, error) {
+ return doSave("", req)
+}
+
+func doSave(file string, req *http.Request) (*http.Response, error) {
+ resp, err := http.DefaultClient.Do(req)
+ if err != nil {
+ return nil, err
+ }
+ data, err := ioutil.ReadAll(resp.Body)
+ resp.Body.Close()
+ if err != nil {
+ return nil, err
+ }
+ resp.Body = ioutil.NopCloser(bytes.NewReader(data))
+
+ var f *os.File
+ if file == "" {
+ f = os.Stderr
+ } else {
+ f, err = os.OpenFile(file, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ }
+
+ fmt.Fprintf(f, "GET %s\n", req.URL.String())
+ fmt.Fprintf(f, "%s\n", resp.Status)
+ var keys []string
+ for k := range resp.Header {
+ keys = append(keys, k)
+ }
+ sort.Strings(keys)
+ for _, k := range keys {
+ if k == "Set-Cookie" {
+ continue
+ }
+ for _, v := range resp.Header[k] {
+ fmt.Fprintf(f, "%s: %s\n", k, v)
+ }
+ }
+ fmt.Fprintf(f, "\n")
+ if utf8.Valid(data) && !bytes.Contains(data, []byte("\nGET")) && !isHexDump(data) {
+ fmt.Fprintf(f, "%s\n\n", data)
+ } else {
+ fmt.Fprintf(f, "%s\n", hex.Dump(data))
+ }
+ return resp, err
+}
+
+var loaded struct {
+ mu sync.Mutex
+ did map[string]bool
+}
+
+func LoadOnce(file string) {
+ loaded.mu.Lock()
+ if loaded.did[file] {
+ loaded.mu.Unlock()
+ return
+ }
+ if loaded.did == nil {
+ loaded.did = make(map[string]bool)
+ }
+ loaded.did[file] = true
+ loaded.mu.Unlock()
+
+ f, err := os.Open(file)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ b := bufio.NewReader(f)
+ var ungetLine string
+ nextLine := func() string {
+ if ungetLine != "" {
+ l := ungetLine
+ ungetLine = ""
+ return l
+ }
+ line, err := b.ReadString('\n')
+ if err != nil {
+ if err == io.EOF {
+ return ""
+ }
+ log.Fatalf("%s: unexpected read error: %v", file, err)
+ }
+ return line
+ }
+
+ for {
+ line := nextLine()
+ if line == "" { // EOF
+ break
+ }
+ line = strings.TrimSpace(line)
+ if strings.HasPrefix(line, "#") || line == "" {
+ continue
+ }
+ if !strings.HasPrefix(line, "GET ") {
+ log.Fatalf("%s: malformed GET line: %s", file, line)
+ }
+ url := line[len("GET "):]
+ status := nextLine()
+ if _, err := strconv.Atoi(strings.Fields(status)[0]); err != nil {
+ log.Fatalf("%s: malformed status line (after GET %s): %s", file, url, status)
+ }
+ hdr := make(http.Header)
+ for {
+ kv := strings.TrimSpace(nextLine())
+ if kv == "" {
+ break
+ }
+ i := strings.Index(kv, ":")
+ if i < 0 {
+ log.Fatalf("%s: malformed header line (after GET %s): %s", file, url, kv)
+ }
+ k, v := kv[:i], strings.TrimSpace(kv[i+1:])
+ hdr[k] = append(hdr[k], v)
+ }
+
+ var body []byte
+ Body:
+ for n := 0; ; n++ {
+ line := nextLine()
+ if n == 0 && isHexDump([]byte(line)) {
+ ungetLine = line
+ b, err := parseHexDump(nextLine)
+ if err != nil {
+ log.Fatalf("%s: malformed hex dump (after GET %s): %v", file, url, err)
+ }
+ body = b
+ break
+ }
+ if line == "" { // EOF
+ for i := 0; i < 2; i++ {
+ if len(body) > 0 && body[len(body)-1] == '\n' {
+ body = body[:len(body)-1]
+ }
+ }
+ break
+ }
+ body = append(body, line...)
+ for line == "\n" {
+ line = nextLine()
+ if strings.HasPrefix(line, "GET ") {
+ ungetLine = line
+ body = body[:len(body)-1]
+ if len(body) > 0 {
+ body = body[:len(body)-1]
+ }
+ break Body
+ }
+ body = append(body, line...)
+ }
+ }
+
+ Serve(url, status, hdr, body)
+ }
+}
+
+func isHexDump(data []byte) bool {
+ return bytes.HasPrefix(data, []byte("00000000 ")) || bytes.HasPrefix(data, []byte("0000000 "))
+}
+
+// parseHexDump parses the hex dump in text, which should be the
+// output of "hexdump -C" or Plan 9's "xd -b" or Go's hex.Dump
+// and returns the original data used to produce the dump.
+// It is meant to enable storing golden binary files as text, so that
+// changes to the golden files can be seen during code reviews.
+func parseHexDump(nextLine func() string) ([]byte, error) {
+ var out []byte
+ for {
+ line := nextLine()
+ if line == "" || line == "\n" {
+ break
+ }
+ if i := strings.Index(line, "|"); i >= 0 { // remove text dump
+ line = line[:i]
+ }
+ f := strings.Fields(line)
+ if len(f) > 1+16 {
+ return nil, fmt.Errorf("parsing hex dump: too many fields on line %q", line)
+ }
+ if len(f) == 0 || len(f) == 1 && f[0] == "*" { // all zeros block omitted
+ continue
+ }
+ addr64, err := strconv.ParseUint(f[0], 16, 0)
+ if err != nil {
+ return nil, fmt.Errorf("parsing hex dump: invalid address %q", f[0])
+ }
+ addr := int(addr64)
+ if len(out) < addr {
+ out = append(out, make([]byte, addr-len(out))...)
+ }
+ for _, x := range f[1:] {
+ val, err := strconv.ParseUint(x, 16, 8)
+ if err != nil {
+ return nil, fmt.Errorf("parsing hexdump: invalid hex byte %q", x)
+ }
+ out = append(out, byte(val))
+ }
+ }
+ return out, nil
+}
diff --git a/src/cmd/go/internal/work/action.go b/src/cmd/go/internal/work/action.go
index 3b5c4d65fd..8edf55ffa1 100644
--- a/src/cmd/go/internal/work/action.go
+++ b/src/cmd/go/internal/work/action.go
@@ -82,9 +82,10 @@ type Action struct {
actionID cache.ActionID // cache ID of action input
buildID string // build ID of action output
- needVet bool // Mode=="build": need to fill in vet config
- vetCfg *vetConfig // vet config
- output []byte // output redirect buffer (nil means use b.Print)
+ VetxOnly bool // Mode=="vet": only being called to supply info about dependencies
+ needVet bool // Mode=="build": need to fill in vet config
+ vetCfg *vetConfig // vet config
+ output []byte // output redirect buffer (nil means use b.Print)
// Execution state.
pending int // number of deps yet to complete
@@ -141,6 +142,7 @@ type actionJSON struct {
Priority int `json:",omitempty"`
Failed bool `json:",omitempty"`
Built string `json:",omitempty"`
+ VetxOnly bool `json:",omitempty"`
}
// cacheKey is the key for the action cache.
@@ -180,6 +182,7 @@ func actionGraphJSON(a *Action) string {
Failed: a.Failed,
Priority: a.priority,
Built: a.built,
+ VetxOnly: a.VetxOnly,
}
if a.Package != nil {
// TODO(rsc): Make this a unique key for a.Package somehow.
@@ -383,6 +386,12 @@ func (b *Builder) CompileAction(mode, depMode BuildMode, p *load.Package) *Actio
// If the caller may be causing p to be installed, it is up to the caller
// to make sure that the install depends on (runs after) vet.
func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
+ a := b.vetAction(mode, depMode, p)
+ a.VetxOnly = false
+ return a
+}
+
+func (b *Builder) vetAction(mode, depMode BuildMode, p *load.Package) *Action {
// Construct vet action.
a := b.cacheAction("vet", p, func() *Action {
a1 := b.CompileAction(mode, depMode, p)
@@ -394,11 +403,18 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
stk.Pop()
aFmt := b.CompileAction(ModeBuild, depMode, p1)
+ deps := []*Action{a1, aFmt}
+ for _, p1 := range load.PackageList(p.Internal.Imports) {
+ deps = append(deps, b.vetAction(mode, depMode, p1))
+ }
+
a := &Action{
- Mode: "vet",
- Package: p,
- Deps: []*Action{a1, aFmt},
- Objdir: a1.Objdir,
+ Mode: "vet",
+ Package: p,
+ Deps: deps,
+ Objdir: a1.Objdir,
+ VetxOnly: true,
+ IgnoreFail: true, // it's OK if vet of dependencies "fails" (reports problems)
}
if a1.Func == nil {
// Built-in packages like unsafe.
@@ -406,7 +422,6 @@ func (b *Builder) VetAction(mode, depMode BuildMode, p *load.Package) *Action {
}
a1.needVet = true
a.Func = (*Builder).vet
-
return a
})
return a
diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go
index 5cb0c2431f..35ff25027e 100644
--- a/src/cmd/go/internal/work/build.go
+++ b/src/cmd/go/internal/work/build.go
@@ -18,6 +18,7 @@ import (
"cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/load"
+ "cmd/go/internal/search"
)
var CmdBuild = &base.Command{
@@ -376,7 +377,7 @@ func libname(args []string, pkgs []*load.Package) (string, error) {
}
var haveNonMeta bool
for _, arg := range args {
- if load.IsMetaPackage(arg) {
+ if search.IsMetaPackage(arg) {
appendName(arg)
} else {
haveNonMeta = true
diff --git a/src/cmd/go/internal/work/buildid.go b/src/cmd/go/internal/work/buildid.go
index f1c538c309..9a2528b914 100644
--- a/src/cmd/go/internal/work/buildid.go
+++ b/src/cmd/go/internal/work/buildid.go
@@ -174,20 +174,29 @@ func (b *Builder) toolID(name string) string {
return id
}
- cmdline := str.StringList(cfg.BuildToolexec, base.Tool(name), "-V=full")
+ path := base.Tool(name)
+ desc := "go tool " + name
+
+ // Special case: undocumented -vettool overrides usual vet, for testing vet.
+ if name == "vet" && VetTool != "" {
+ path = VetTool
+ desc = VetTool
+ }
+
+ cmdline := str.StringList(cfg.BuildToolexec, path, "-V=full")
cmd := exec.Command(cmdline[0], cmdline[1:]...)
cmd.Env = base.EnvForDir(cmd.Dir, os.Environ())
var stdout, stderr bytes.Buffer
cmd.Stdout = &stdout
cmd.Stderr = &stderr
if err := cmd.Run(); err != nil {
- base.Fatalf("go tool %s: %v\n%s%s", name, err, stdout.Bytes(), stderr.Bytes())
+ base.Fatalf("%s: %v\n%s%s", desc, err, stdout.Bytes(), stderr.Bytes())
}
line := stdout.String()
f := strings.Fields(line)
- if len(f) < 3 || f[0] != name || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") {
- base.Fatalf("go tool %s -V=full: unexpected output:\n\t%s", name, line)
+ if len(f) < 3 || f[0] != name && path != VetTool || f[1] != "version" || f[2] == "devel" && !strings.HasPrefix(f[len(f)-1], "buildID=") {
+ base.Fatalf("%s -V=full: unexpected output:\n\t%s", desc, line)
}
if f[2] == "devel" {
// On the development branch, use the content ID part of the build ID.
@@ -294,13 +303,32 @@ func (b *Builder) gccgoToolID(name, language string) (string, error) {
return id, nil
}
+// Check if assembler used by gccgo is GNU as.
+func assemblerIsGas() bool {
+ cmd := exec.Command(BuildToolchain.compiler(), "-print-prog-name=as")
+ assembler, err := cmd.Output()
+ if err == nil {
+ cmd := exec.Command(strings.TrimSpace(string(assembler)), "--version")
+ out, err := cmd.Output()
+ return err == nil && strings.Contains(string(out), "GNU")
+ } else {
+ return false
+ }
+}
+
// gccgoBuildIDELFFile creates an assembler file that records the
// action's build ID in an SHF_EXCLUDE section.
func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
sfile := a.Objdir + "_buildid.s"
var buf bytes.Buffer
- fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n")
+ if cfg.Goos != "solaris" || assemblerIsGas() {
+ fmt.Fprintf(&buf, "\t"+`.section .go.buildid,"e"`+"\n")
+ } else if cfg.Goarch == "sparc" || cfg.Goarch == "sparc64" {
+ fmt.Fprintf(&buf, "\t"+`.section ".go.buildid",#exclude`+"\n")
+ } else { // cfg.Goarch == "386" || cfg.Goarch == "amd64"
+ fmt.Fprintf(&buf, "\t"+`.section .go.buildid,#exclude`+"\n")
+ }
fmt.Fprintf(&buf, "\t.byte ")
for i := 0; i < len(a.buildID); i++ {
if i > 0 {
@@ -313,8 +341,10 @@ func (b *Builder) gccgoBuildIDELFFile(a *Action) (string, error) {
fmt.Fprintf(&buf, "%#02x", a.buildID[i])
}
fmt.Fprintf(&buf, "\n")
- fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n")
- fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n")
+ if cfg.Goos != "solaris" {
+ fmt.Fprintf(&buf, "\t"+`.section .note.GNU-stack,"",@progbits`+"\n")
+ fmt.Fprintf(&buf, "\t"+`.section .note.GNU-split-stack,"",@progbits`+"\n")
+ }
if cfg.BuildN || cfg.BuildX {
for _, line := range bytes.Split(buf.Bytes(), []byte("\n")) {
@@ -488,14 +518,9 @@ func (b *Builder) useCache(a *Action, p *load.Package, actionHash cache.ActionID
// but we're still happy to use results from the build artifact cache.
if c := cache.Default(); c != nil {
if !cfg.BuildA {
- entry, err := c.Get(actionHash)
- if err == nil {
- file := c.OutputFile(entry.OutputID)
- info, err1 := os.Stat(file)
- buildID, err2 := buildid.ReadFile(file)
- if err1 == nil && err2 == nil && info.Size() == entry.Size {
- stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout"))
- if err == nil {
+ if file, _, err := c.GetFile(actionHash); err == nil {
+ if buildID, err := buildid.ReadFile(file); err == nil {
+ if stdout, stdoutEntry, err := c.GetBytes(cache.Subkey(a.actionID, "stdout")); err == nil {
if len(stdout) > 0 {
if cfg.BuildX || cfg.BuildN {
b.Showcmd("", "%s # internal", joinUnambiguously(str.StringList("cat", c.OutputFile(stdoutEntry.OutputID))))
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 5fd2f66b86..5c4dc88821 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -30,8 +30,15 @@ import (
"cmd/go/internal/cfg"
"cmd/go/internal/load"
"cmd/go/internal/str"
+ "cmd/go/internal/vgo"
)
+func init() {
+ vgo.InstallHook = func(args []string) {
+ CmdInstall.Run(CmdInstall, args)
+ }
+}
+
// actionList returns the list of actions in the dag rooted at root
// as visited in a depth-first post-order traversal.
func actionList(root *Action) []*Action {
@@ -599,6 +606,13 @@ func (b *Builder) build(a *Action) (err error) {
fmt.Fprintf(&icfg, "packagefile %s=%s\n", p1.ImportPath, a1.built)
}
+ if p.Internal.BuildInfo != "" {
+ if err := b.writeFile(objdir+"_gomod_.go", vgo.ModInfoProg(p.Internal.BuildInfo)); err != nil {
+ return err
+ }
+ gofiles = append(gofiles, objdir+"_gomod_.go")
+ }
+
// Compile Go.
objpkg := objdir + "_pkg_.a"
ofile, out, err := BuildToolchain.gc(b, a, objpkg, icfg.Bytes(), len(sfiles) > 0, gofiles)
@@ -718,16 +732,11 @@ func (b *Builder) cacheObjdirFile(a *Action, c *cache.Cache, name string) error
}
func (b *Builder) findCachedObjdirFile(a *Action, c *cache.Cache, name string) (string, error) {
- entry, err := c.Get(cache.Subkey(a.actionID, name))
+ file, _, err := c.GetFile(cache.Subkey(a.actionID, name))
if err != nil {
return "", err
}
- out := c.OutputFile(entry.OutputID)
- info, err := os.Stat(out)
- if err != nil || info.Size() != entry.Size {
- return "", fmt.Errorf("not in cache")
- }
- return out, nil
+ return file, nil
}
func (b *Builder) loadCachedObjdirFile(a *Action, c *cache.Cache, name string) error {
@@ -833,16 +842,21 @@ func (b *Builder) loadCachedCgoFiles(a *Action) bool {
return true
}
+// vetConfig is the configuration passed to vet describing a single package.
type vetConfig struct {
- Compiler string
- Dir string
- GoFiles []string
- ImportMap map[string]string
- PackageFile map[string]string
- Standard map[string]bool
- ImportPath string
+ Compiler string // compiler name (gc, gccgo)
+ Dir string // directory containing package
+ ImportPath string // canonical import path ("package path")
+ GoFiles []string // absolute paths to package source files
+
+ ImportMap map[string]string // map import path in source code to package path
+ PackageFile map[string]string // map package path to .a file with export data
+ Standard map[string]bool // map package path to whether it's in the standard library
+ PackageVetx map[string]string // map package path to vetx data from earlier vet run
+ VetxOnly bool // only compute vetx data; don't report detected problems
+ VetxOutput string // write vetx data to this output file
- SucceedOnTypecheckFailure bool
+ SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
}
func buildVetConfig(a *Action, gofiles []string) {
@@ -903,6 +917,8 @@ func (b *Builder) vet(a *Action) error {
// a.Deps[0] is the build of the package being vetted.
// a.Deps[1] is the build of the "fmt" package.
+ a.Failed = false // vet of dependency may have failed but we can still succeed
+
vcfg := a.Deps[0].vetCfg
if vcfg == nil {
// Vet config should only be missing if the build failed.
@@ -912,6 +928,38 @@ func (b *Builder) vet(a *Action) error {
return nil
}
+ vcfg.VetxOnly = a.VetxOnly
+ vcfg.VetxOutput = a.Objdir + "vet.out"
+ vcfg.PackageVetx = make(map[string]string)
+
+ h := cache.NewHash("vet " + a.Package.ImportPath)
+ fmt.Fprintf(h, "vet %q\n", b.toolID("vet"))
+
+ // Note: We could decide that vet should compute export data for
+ // all analyses, in which case we don't need to include the flags here.
+ // But that would mean that if an analysis causes problems like
+ // unexpected crashes there would be no way to turn it off.
+ // It seems better to let the flags disable export analysis too.
+ fmt.Fprintf(h, "vetflags %q\n", VetFlags)
+
+ fmt.Fprintf(h, "pkg %q\n", a.Deps[0].actionID)
+ for _, a1 := range a.Deps {
+ if a1.Mode == "vet" && a1.built != "" {
+ fmt.Fprintf(h, "vetout %q %s\n", a1.Package.ImportPath, b.fileHash(a1.built))
+ vcfg.PackageVetx[a1.Package.ImportPath] = a1.built
+ }
+ }
+ key := cache.ActionID(h.Sum())
+
+ if vcfg.VetxOnly {
+ if c := cache.Default(); c != nil && !cfg.BuildA {
+ if file, _, err := c.GetFile(key); err == nil {
+ a.built = file
+ return nil
+ }
+ }
+ }
+
if vcfg.ImportMap["fmt"] == "" {
a1 := a.Deps[1]
vcfg.ImportMap["fmt"] = "fmt"
@@ -949,7 +997,18 @@ func (b *Builder) vet(a *Action) error {
if tool == "" {
tool = base.Tool("vet")
}
- return b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg")
+ runErr := b.run(a, p.Dir, p.ImportPath, env, cfg.BuildToolexec, tool, VetFlags, a.Objdir+"vet.cfg")
+
+ // If vet wrote export data, save it for input to future vets.
+ if f, err := os.Open(vcfg.VetxOutput); err == nil {
+ a.built = vcfg.VetxOutput
+ if c := cache.Default(); c != nil {
+ c.Put(key, f)
+ }
+ f.Close()
+ }
+
+ return runErr
}
// linkActionID computes the action ID for a link action.
diff --git a/src/cmd/go/internal/work/init.go b/src/cmd/go/internal/work/init.go
index 4d3c5cbd17..1081e5147e 100644
--- a/src/cmd/go/internal/work/init.go
+++ b/src/cmd/go/internal/work/init.go
@@ -43,11 +43,16 @@ func instrumentInit() {
fmt.Fprintf(os.Stderr, "-msan is not supported on %s/%s\n", cfg.Goos, cfg.Goarch)
os.Exit(2)
}
- if cfg.BuildRace && (cfg.Goarch != "amd64" || cfg.Goos != "linux" && cfg.Goos != "freebsd" && cfg.Goos != "darwin" && cfg.Goos != "windows") {
- fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
- os.Exit(2)
+ if cfg.BuildRace {
+ platform := cfg.Goos + "/" + cfg.Goarch
+ switch platform {
+ default:
+ fmt.Fprintf(os.Stderr, "go %s: -race is only supported on linux/amd64, linux/ppc64le, freebsd/amd64, darwin/amd64 and windows/amd64\n", flag.Args()[0])
+ os.Exit(2)
+ case "linux/amd64", "linux/ppc64le", "freebsd/amd64", "darwin/amd64", "windows/amd64":
+ // race supported on these platforms
+ }
}
-
mode := "race"
if cfg.BuildMSan {
mode = "msan"
diff --git a/src/cmd/go/testdata/badmod/go.mod b/src/cmd/go/testdata/badmod/go.mod
new file mode 100644
index 0000000000..f7f6423870
--- /dev/null
+++ b/src/cmd/go/testdata/badmod/go.mod
@@ -0,0 +1 @@
+module m
diff --git a/src/cmd/go/testdata/badmod/x.go b/src/cmd/go/testdata/badmod/x.go
new file mode 100644
index 0000000000..579fb086ee
--- /dev/null
+++ b/src/cmd/go/testdata/badmod/x.go
@@ -0,0 +1,4 @@
+package x
+
+import _ "appengine"
+import _ "nonexistent.rsc.io" // domain does not exist
diff --git a/src/cmd/go/testdata/src/vetfail/p1/p1.go b/src/cmd/go/testdata/src/vetfail/p1/p1.go
index 248317b779..eaa9b18333 100644
--- a/src/cmd/go/testdata/src/vetfail/p1/p1.go
+++ b/src/cmd/go/testdata/src/vetfail/p1/p1.go
@@ -1,3 +1,5 @@
+// +build !foo-bar
+
package p1
import "fmt"
diff --git a/src/cmd/go/testdata/vendormod/go.mod b/src/cmd/go/testdata/vendormod/go.mod
new file mode 100644
index 0000000000..6f71634253
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/go.mod
@@ -0,0 +1,16 @@
+module m
+
+replace x v1.0.0 => ./x
+
+replace y v1.0.0 => ./y
+
+replace z v1.0.0 => ./z
+
+replace w v1.0.0 => ./w
+
+require (
+ w v1.0.0
+ x v1.0.0
+ y v1.0.0
+ z v1.0.0
+)
diff --git a/src/cmd/go/testdata/vendormod/v1.go b/src/cmd/go/testdata/vendormod/v1.go
new file mode 100644
index 0000000000..6ca04a5aac
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/v1.go
@@ -0,0 +1,3 @@
+package m
+
+import _ "x"
diff --git a/src/cmd/go/testdata/vendormod/v2.go b/src/cmd/go/testdata/vendormod/v2.go
new file mode 100644
index 0000000000..8b089e4365
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/v2.go
@@ -0,0 +1,5 @@
+// +build abc
+
+package mMmMmMm
+
+import _ "y"
diff --git a/src/cmd/go/testdata/vendormod/v3.go b/src/cmd/go/testdata/vendormod/v3.go
new file mode 100644
index 0000000000..318b5f0303
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/v3.go
@@ -0,0 +1,5 @@
+// +build !abc
+
+package m
+
+import _ "z"
diff --git a/src/cmd/go/testdata/vendormod/w/go.mod b/src/cmd/go/testdata/vendormod/w/go.mod
new file mode 100644
index 0000000000..ce2a6c161c
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/w/go.mod
@@ -0,0 +1 @@
+module w
diff --git a/src/cmd/go/testdata/vendormod/w/w.go b/src/cmd/go/testdata/vendormod/w/w.go
new file mode 100644
index 0000000000..a796c0b5f4
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/w/w.go
@@ -0,0 +1 @@
+package w
diff --git a/src/cmd/go/testdata/vendormod/x/go.mod b/src/cmd/go/testdata/vendormod/x/go.mod
new file mode 100644
index 0000000000..c1914353d5
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/x/go.mod
@@ -0,0 +1 @@
+module x
diff --git a/src/cmd/go/testdata/vendormod/x/x.go b/src/cmd/go/testdata/vendormod/x/x.go
new file mode 100644
index 0000000000..823aafd071
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/x/x.go
@@ -0,0 +1 @@
+package x
diff --git a/src/cmd/go/testdata/vendormod/y/go.mod b/src/cmd/go/testdata/vendormod/y/go.mod
new file mode 100644
index 0000000000..ac82a48598
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/y/go.mod
@@ -0,0 +1 @@
+module y
diff --git a/src/cmd/go/testdata/vendormod/y/y.go b/src/cmd/go/testdata/vendormod/y/y.go
new file mode 100644
index 0000000000..789ca715ec
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/y/y.go
@@ -0,0 +1 @@
+package y
diff --git a/src/cmd/go/testdata/vendormod/z/go.mod b/src/cmd/go/testdata/vendormod/z/go.mod
new file mode 100644
index 0000000000..efc58fedd0
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/z/go.mod
@@ -0,0 +1 @@
+module z
diff --git a/src/cmd/go/testdata/vendormod/z/z.go b/src/cmd/go/testdata/vendormod/z/z.go
new file mode 100644
index 0000000000..46458cbddb
--- /dev/null
+++ b/src/cmd/go/testdata/vendormod/z/z.go
@@ -0,0 +1 @@
+package z
diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go
index 8e725c6f2c..9be0183edf 100644
--- a/src/cmd/internal/obj/arm64/a.out.go
+++ b/src/cmd/internal/obj/arm64/a.out.go
@@ -594,6 +594,8 @@ const (
AHVC
AIC
AISB
+ ALDADDALD
+ ALDADDALW
ALDADDB
ALDADDH
ALDADDW
diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go
index 30be3b2732..0579e5362e 100644
--- a/src/cmd/internal/obj/arm64/anames.go
+++ b/src/cmd/internal/obj/arm64/anames.go
@@ -96,6 +96,8 @@ var Anames = []string{
"HVC",
"IC",
"ISB",
+ "LDADDALD",
+ "LDADDALW",
"LDADDB",
"LDADDH",
"LDADDW",
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index e727143757..192d65df96 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -2011,6 +2011,8 @@ func buildop(ctxt *obj.Link) {
oprangeset(ASWPB, t)
oprangeset(ASWPH, t)
oprangeset(ASWPW, t)
+ oprangeset(ALDADDALD, t)
+ oprangeset(ALDADDALW, t)
oprangeset(ALDADDB, t)
oprangeset(ALDADDH, t)
oprangeset(ALDADDW, t)
@@ -3363,9 +3365,9 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
rt := p.RegTo2
rb := p.To.Reg
switch p.As {
- case ASWPD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit
+ case ASWPD, ALDADDALD, ALDADDD, ALDANDD, ALDEORD, ALDORD: // 64-bit
o1 = 3 << 30
- case ASWPW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit
+ case ASWPW, ALDADDALW, ALDADDW, ALDANDW, ALDEORW, ALDORW: // 32-bit
o1 = 2 << 30
case ASWPH, ALDADDH, ALDANDH, ALDEORH, ALDORH: // 16-bit
o1 = 1 << 30
@@ -3377,7 +3379,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
switch p.As {
case ASWPD, ASWPW, ASWPH, ASWPB:
o1 |= 0x20 << 10
- case ALDADDD, ALDADDW, ALDADDH, ALDADDB:
+ case ALDADDALD, ALDADDALW, ALDADDD, ALDADDW, ALDADDH, ALDADDB:
o1 |= 0x00 << 10
case ALDANDD, ALDANDW, ALDANDH, ALDANDB:
o1 |= 0x04 << 10
@@ -3386,6 +3388,10 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
case ALDORD, ALDORW, ALDORH, ALDORB:
o1 |= 0x0c << 10
}
+ switch p.As {
+ case ALDADDALD, ALDADDALW:
+ o1 |= 3 << 22
+ }
o1 |= 0x1c1<<21 | uint32(rs&31)<<16 | uint32(rb&31)<<5 | uint32(rt&31)
case 50: /* sys/sysl */
diff --git a/src/cmd/internal/obj/ppc64/obj9.go b/src/cmd/internal/obj/ppc64/obj9.go
index 7bb21ab439..f42d675805 100644
--- a/src/cmd/internal/obj/ppc64/obj9.go
+++ b/src/cmd/internal/obj/ppc64/obj9.go
@@ -502,7 +502,10 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q = c.stacksplit(q, autosize) // emit split check
}
- if autosize != 0 {
+ // Special handling of the racecall thunk. Assume that its asm code will
+ // save the link register and update the stack, since that code is
+ // called directly from C/C++ and can't clobber REGTMP (R31).
+ if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
// Save the link register and update the SP. MOVDU is used unless
// the frame size is too large. The link register must be saved
// even for non-empty leaf functions so that traceback works.
@@ -678,7 +681,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
retTarget := p.To.Sym
if c.cursym.Func.Text.Mark&LEAF != 0 {
- if autosize == 0 {
+ if autosize == 0 || c.cursym.Name == "runtime.racecallbackthunk" {
p.As = ABR
p.From = obj.Addr{}
if retTarget == nil {
@@ -747,8 +750,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p.Link = q
p = q
}
-
- if autosize != 0 {
+ prev := p
+ if autosize != 0 && c.cursym.Name != "runtime.racecallbackthunk" {
q = c.newprog()
q.As = AADD
q.Pos = p.Pos
@@ -759,7 +762,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.Spadj = -autosize
q.Link = p.Link
- p.Link = q
+ prev.Link = q
+ prev = q
}
q1 = c.newprog()
@@ -776,7 +780,7 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.Spadj = +autosize
q1.Link = q.Link
- q.Link = q1
+ prev.Link = q1
case AADD:
if p.To.Type == obj.TYPE_REG && p.To.Reg == REGSP && p.From.Type == obj.TYPE_CONST {
p.Spadj = int32(-p.From.Offset)
diff --git a/src/cmd/internal/obj/wasm/a.out.go b/src/cmd/internal/obj/wasm/a.out.go
index 9c04be2609..6f882215ff 100644
--- a/src/cmd/internal/obj/wasm/a.out.go
+++ b/src/cmd/internal/obj/wasm/a.out.go
@@ -219,6 +219,8 @@ const (
// However, it is not allowed to switch goroutines while inside of an ACALLNORESUME call.
ACALLNORESUME
+ ARETUNWIND
+
AMOVB
AMOVH
AMOVW
@@ -244,6 +246,7 @@ const (
REG_RET1
REG_RET2
REG_RET3
+ REG_RUN
// locals
REG_R0
diff --git a/src/cmd/internal/obj/wasm/anames.go b/src/cmd/internal/obj/wasm/anames.go
index 20d04446d0..745f0d773a 100644
--- a/src/cmd/internal/obj/wasm/anames.go
+++ b/src/cmd/internal/obj/wasm/anames.go
@@ -180,6 +180,7 @@ var Anames = []string{
"F64ReinterpretI64",
"RESUMEPOINT",
"CALLNORESUME",
+ "RETUNWIND",
"MOVB",
"MOVH",
"MOVW",
diff --git a/src/cmd/internal/obj/wasm/wasmobj.go b/src/cmd/internal/obj/wasm/wasmobj.go
index ca09b3fa0b..8498b40724 100644
--- a/src/cmd/internal/obj/wasm/wasmobj.go
+++ b/src/cmd/internal/obj/wasm/wasmobj.go
@@ -25,6 +25,7 @@ var Register = map[string]int16{
"RET1": REG_RET1,
"RET2": REG_RET2,
"RET3": REG_RET3,
+ "RUN": REG_RUN,
"R0": REG_R0,
"R1": REG_R1,
@@ -487,7 +488,7 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
p = appendp(p, AEnd) // end of Loop
}
- case obj.ARET:
+ case obj.ARET, ARETUNWIND:
ret := *p
p.As = obj.ANOP
@@ -528,7 +529,14 @@ func preprocess(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
p = appendp(p, AI32Add)
p = appendp(p, ASet, regAddr(REG_SP))
- // not switching goroutine, return 0
+ if ret.As == ARETUNWIND {
+ // function needs to unwind the WebAssembly stack, return 1
+ p = appendp(p, AI32Const, constAddr(1))
+ p = appendp(p, AReturn)
+ break
+ }
+
+ // not unwinding the WebAssembly stack, return 0
p = appendp(p, AI32Const, constAddr(0))
p = appendp(p, AReturn)
}
@@ -726,7 +734,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
reg := p.From.Reg
switch {
- case reg >= REG_PC_F && reg <= REG_RET3:
+ case reg >= REG_PC_F && reg <= REG_RUN:
w.WriteByte(0x23) // get_global
writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_F15:
@@ -743,7 +751,7 @@ func assemble(ctxt *obj.Link, s *obj.LSym, newprog obj.ProgAlloc) {
}
reg := p.To.Reg
switch {
- case reg >= REG_PC_F && reg <= REG_RET3:
+ case reg >= REG_PC_F && reg <= REG_RUN:
w.WriteByte(0x24) // set_global
writeUleb128(w, uint64(reg-REG_PC_F))
case reg >= REG_R0 && reg <= REG_F15:
diff --git a/src/cmd/link/doc.go b/src/cmd/link/doc.go
index d61b66a938..963d86a35f 100644
--- a/src/cmd/link/doc.go
+++ b/src/cmd/link/doc.go
@@ -39,8 +39,10 @@ Flags:
Print linker version and exit.
-X importpath.name=value
Set the value of the string variable in importpath named name to value.
+ This is only effective if the variable is declared in the source code either uninitialized
+ or initialized to a constant string expression. -X will not work if the initializer makes
+ a function call or refers to other variables.
Note that before Go 1.5 this option took two separate arguments.
- Now it takes one argument split on the first = sign.
-buildmode mode
Set build mode (default exe).
-cpuprofile file
diff --git a/src/cmd/link/internal/ld/config.go b/src/cmd/link/internal/ld/config.go
index 6685ad50ac..18fbea62ee 100644
--- a/src/cmd/link/internal/ld/config.go
+++ b/src/cmd/link/internal/ld/config.go
@@ -196,6 +196,13 @@ func mustLinkExternal(ctxt *Link) (res bool, reason string) {
return true, objabi.GOARCH + " does not support internal cgo"
}
+ // When the race flag is set, the LLVM tsan relocatable file is linked
+ // into the final binary, which means external linking is required because
+ // internal linking does not support it.
+ if *flagRace && ctxt.Arch.InFamily(sys.PPC64) {
+ return true, "race on ppc64le"
+ }
+
// Some build modes require work the internal linker cannot do (yet).
switch ctxt.BuildMode {
case BuildModeCArchive:
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index be65b7be06..c337c5e7ed 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -32,10 +32,13 @@
package ld
import (
+ "bytes"
"cmd/internal/gcprog"
"cmd/internal/objabi"
"cmd/internal/sys"
"cmd/link/internal/sym"
+ "compress/zlib"
+ "encoding/binary"
"fmt"
"log"
"os"
@@ -679,6 +682,10 @@ func blk(ctxt *Link, syms []*sym.Symbol, addr, size int64, pad []byte) {
}
}
+ // This doesn't distinguish the memory size from the file
+ // size, and it lays out the file based on Symbol.Value, which
+ // is the virtual address. DWARF compression changes file sizes,
+ // so dwarfcompress will fix this up later if necessary.
eaddr := addr + size
for _, s := range syms {
if s.Attr.SubSymbol() {
@@ -821,6 +828,7 @@ func addstrdata1(ctxt *Link, arg string) {
strdata[name] = value
}
+// addstrdata sets the initial value of the string variable name to value.
func addstrdata(ctxt *Link, name, value string) {
s := ctxt.Syms.ROLookup(name, 0)
if s == nil || s.Gotype == nil {
@@ -1352,9 +1360,8 @@ func (ctxt *Link) dodata() {
/*
* We finished data, begin read-only data.
* Not all systems support a separate read-only non-executable data section.
- * ELF systems do.
+ * ELF and Windows PE systems do.
* OS X and Plan 9 do not.
- * Windows PE may, but if so we have not implemented it.
* And if we're using external linking mode, the point is moot,
* since it's not our decision; that code expects the sections in
* segtext.
@@ -1362,6 +1369,8 @@ func (ctxt *Link) dodata() {
var segro *sym.Segment
if ctxt.IsELF && ctxt.LinkMode == LinkInternal {
segro = &Segrodata
+ } else if ctxt.HeadType == objabi.Hwindows {
+ segro = &Segrodata
} else {
segro = &Segtext
}
@@ -1902,12 +1911,15 @@ func assignAddress(ctxt *Link, sect *sym.Section, n int, s *sym.Symbol, va uint6
return sect, n, va
}
-// assign addresses
-func (ctxt *Link) address() {
+// address assigns virtual addresses to all segments and sections and
+// returns all segments in file order.
+func (ctxt *Link) address() []*sym.Segment {
+ var order []*sym.Segment // Layout order
+
va := uint64(*FlagTextAddr)
+ order = append(order, &Segtext)
Segtext.Rwx = 05
Segtext.Vaddr = va
- Segtext.Fileoff = uint64(HEADR)
for _, s := range Segtext.Sections {
va = uint64(Rnd(int64(va), int64(s.Align)))
s.Vaddr = va
@@ -1915,7 +1927,6 @@ func (ctxt *Link) address() {
}
Segtext.Length = va - uint64(*FlagTextAddr)
- Segtext.Filelen = Segtext.Length
if ctxt.HeadType == objabi.Hnacl {
va += 32 // room for the "halt sled"
}
@@ -1936,10 +1947,9 @@ func (ctxt *Link) address() {
// writable even for this short period.
va = uint64(Rnd(int64(va), int64(*FlagRound)))
+ order = append(order, &Segrodata)
Segrodata.Rwx = 04
Segrodata.Vaddr = va
- Segrodata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
- Segrodata.Filelen = 0
for _, s := range Segrodata.Sections {
va = uint64(Rnd(int64(va), int64(s.Align)))
s.Vaddr = va
@@ -1947,17 +1957,15 @@ func (ctxt *Link) address() {
}
Segrodata.Length = va - Segrodata.Vaddr
- Segrodata.Filelen = Segrodata.Length
}
if len(Segrelrodata.Sections) > 0 {
// align to page boundary so as not to mix
// rodata, rel-ro data, and executable text.
va = uint64(Rnd(int64(va), int64(*FlagRound)))
+ order = append(order, &Segrelrodata)
Segrelrodata.Rwx = 06
Segrelrodata.Vaddr = va
- Segrelrodata.Fileoff = va - Segrodata.Vaddr + Segrodata.Fileoff
- Segrelrodata.Filelen = 0
for _, s := range Segrelrodata.Sections {
va = uint64(Rnd(int64(va), int64(s.Align)))
s.Vaddr = va
@@ -1965,20 +1973,12 @@ func (ctxt *Link) address() {
}
Segrelrodata.Length = va - Segrelrodata.Vaddr
- Segrelrodata.Filelen = Segrelrodata.Length
}
va = uint64(Rnd(int64(va), int64(*FlagRound)))
+ order = append(order, &Segdata)
Segdata.Rwx = 06
Segdata.Vaddr = va
- Segdata.Fileoff = va - Segtext.Vaddr + Segtext.Fileoff
- Segdata.Filelen = 0
- if ctxt.HeadType == objabi.Hwindows {
- Segdata.Fileoff = Segtext.Fileoff + uint64(Rnd(int64(Segtext.Length), PEFILEALIGN))
- }
- if ctxt.HeadType == objabi.Hplan9 {
- Segdata.Fileoff = Segtext.Fileoff + Segtext.Filelen
- }
var data *sym.Section
var noptr *sym.Section
var bss *sym.Section
@@ -2008,16 +2008,14 @@ func (ctxt *Link) address() {
}
}
+ // Assign Segdata's Filelen omitting the BSS. We do this here
+ // simply because right now we know where the BSS starts.
Segdata.Filelen = bss.Vaddr - Segdata.Vaddr
va = uint64(Rnd(int64(va), int64(*FlagRound)))
+ order = append(order, &Segdwarf)
Segdwarf.Rwx = 06
Segdwarf.Vaddr = va
- Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), int64(*FlagRound)))
- Segdwarf.Filelen = 0
- if ctxt.HeadType == objabi.Hwindows {
- Segdwarf.Fileoff = Segdata.Fileoff + uint64(Rnd(int64(Segdata.Filelen), PEFILEALIGN))
- }
for i, s := range Segdwarf.Sections {
vlen := int64(s.Length)
if i+1 < len(Segdwarf.Sections) {
@@ -2031,8 +2029,6 @@ func (ctxt *Link) address() {
Segdwarf.Length = va - Segdwarf.Vaddr
}
- Segdwarf.Filelen = va - Segdwarf.Vaddr
-
var (
text = Segtext.Sections[0]
rodata = ctxt.Syms.Lookup("runtime.rodata", 0).Sect
@@ -2119,6 +2115,41 @@ func (ctxt *Link) address() {
ctxt.xdefine("runtime.noptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr))
ctxt.xdefine("runtime.enoptrbss", sym.SNOPTRBSS, int64(noptrbss.Vaddr+noptrbss.Length))
ctxt.xdefine("runtime.end", sym.SBSS, int64(Segdata.Vaddr+Segdata.Length))
+
+ return order
+}
+
+// layout assigns file offsets and lengths to the segments in order.
+func (ctxt *Link) layout(order []*sym.Segment) {
+ var prev *sym.Segment
+ for _, seg := range order {
+ if prev == nil {
+ seg.Fileoff = uint64(HEADR)
+ } else {
+ switch ctxt.HeadType {
+ default:
+ // Assuming the previous segment was
+ // aligned, the following rounding
+ // should ensure that this segment's
+ // VA ≡ Fileoff mod FlagRound.
+ seg.Fileoff = uint64(Rnd(int64(prev.Fileoff+prev.Filelen), int64(*FlagRound)))
+ if seg.Vaddr%uint64(*FlagRound) != seg.Fileoff%uint64(*FlagRound) {
+ Exitf("bad segment rounding (Vaddr=%#x Fileoff=%#x FlagRound=%#x)", seg.Vaddr, seg.Fileoff, *FlagRound)
+ }
+ case objabi.Hwindows:
+ seg.Fileoff = prev.Fileoff + uint64(Rnd(int64(prev.Filelen), PEFILEALIGN))
+ case objabi.Hplan9:
+ seg.Fileoff = prev.Fileoff + prev.Filelen
+ }
+ }
+ if seg != &Segdata {
+ // Link.address already set Segdata.Filelen to
+ // account for BSS.
+ seg.Filelen = seg.Length
+ }
+ prev = seg
+ }
+
}
// add a trampoline with symbol s (to be laid down after the current function)
@@ -2131,3 +2162,44 @@ func (ctxt *Link) AddTramp(s *sym.Symbol) {
ctxt.Logf("trampoline %s inserted\n", s)
}
}
+
+// compressSyms compresses syms and returns the contents of the
+// compressed section. If the section would get larger, it returns nil.
+func compressSyms(ctxt *Link, syms []*sym.Symbol) []byte {
+ var total int64
+ for _, sym := range syms {
+ total += sym.Size
+ }
+
+ var buf bytes.Buffer
+ buf.Write([]byte("ZLIB"))
+ var sizeBytes [8]byte
+ binary.BigEndian.PutUint64(sizeBytes[:], uint64(total))
+ buf.Write(sizeBytes[:])
+
+ z := zlib.NewWriter(&buf)
+ for _, sym := range syms {
+ if _, err := z.Write(sym.P); err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ for i := sym.Size - int64(len(sym.P)); i > 0; {
+ b := zeros[:]
+ if i < int64(len(b)) {
+ b = b[:i]
+ }
+ n, err := z.Write(b)
+ if err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ i -= int64(n)
+ }
+ }
+ if err := z.Close(); err != nil {
+ log.Fatalf("compression failed: %s", err)
+ }
+ if int64(buf.Len()) >= total {
+ // Compression didn't save any space.
+ return nil
+ }
+ return buf.Bytes()
+}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 328ea1c0f4..830d81d446 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -1908,23 +1908,14 @@ func dwarfaddshstrings(ctxt *Link, shstrtab *sym.Symbol) {
return
}
- Addstring(shstrtab, ".debug_abbrev")
- Addstring(shstrtab, ".debug_frame")
- Addstring(shstrtab, ".debug_info")
- Addstring(shstrtab, ".debug_loc")
- Addstring(shstrtab, ".debug_line")
- Addstring(shstrtab, ".debug_pubnames")
- Addstring(shstrtab, ".debug_pubtypes")
- Addstring(shstrtab, ".debug_gdb_scripts")
- Addstring(shstrtab, ".debug_ranges")
- if ctxt.LinkMode == LinkExternal {
- Addstring(shstrtab, elfRelType+".debug_info")
- Addstring(shstrtab, elfRelType+".debug_loc")
- Addstring(shstrtab, elfRelType+".debug_line")
- Addstring(shstrtab, elfRelType+".debug_frame")
- Addstring(shstrtab, elfRelType+".debug_pubnames")
- Addstring(shstrtab, elfRelType+".debug_pubtypes")
- Addstring(shstrtab, elfRelType+".debug_ranges")
+ secs := []string{"abbrev", "frame", "info", "loc", "line", "pubnames", "pubtypes", "gdb_scripts", "ranges"}
+ for _, sec := range secs {
+ Addstring(shstrtab, ".debug_"+sec)
+ if ctxt.LinkMode == LinkExternal {
+ Addstring(shstrtab, elfRelType+".debug_"+sec)
+ } else {
+ Addstring(shstrtab, ".zdebug_"+sec)
+ }
}
}
@@ -1937,6 +1928,7 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
if ctxt.LinkMode != LinkExternal {
return
}
+
s := ctxt.Syms.Lookup(".debug_info", 0)
putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
s = ctxt.Syms.Lookup(".debug_abbrev", 0)
@@ -1954,3 +1946,63 @@ func dwarfaddelfsectionsyms(ctxt *Link) {
putelfsectionsym(ctxt.Out, s, s.Sect.Elfsect.(*ElfShdr).shnum)
}
}
+
+// dwarfcompress compresses the DWARF sections. This must happen after
+// relocations are applied. After this, dwarfp will contain a
+// different (new) set of symbols, and sections may have been replaced.
+func dwarfcompress(ctxt *Link) {
+ supported := ctxt.IsELF || ctxt.HeadType == objabi.Hwindows || ctxt.HeadType == objabi.Hdarwin
+ if !ctxt.compressDWARF || !supported || ctxt.LinkMode != LinkInternal {
+ return
+ }
+
+ var start int
+ var newDwarfp []*sym.Symbol
+ Segdwarf.Sections = Segdwarf.Sections[:0]
+ for i, s := range dwarfp {
+ // Find the boundaries between sections and compress
+ // the whole section once we've found the last of its
+ // symbols.
+ if i+1 >= len(dwarfp) || s.Sect != dwarfp[i+1].Sect {
+ s1 := compressSyms(ctxt, dwarfp[start:i+1])
+ if s1 == nil {
+ // Compression didn't help.
+ newDwarfp = append(newDwarfp, dwarfp[start:i+1]...)
+ Segdwarf.Sections = append(Segdwarf.Sections, s.Sect)
+ } else {
+ compressedSegName := ".zdebug_" + s.Sect.Name[len(".debug_"):]
+ sect := addsection(ctxt.Arch, &Segdwarf, compressedSegName, 04)
+ sect.Length = uint64(len(s1))
+ newSym := ctxt.Syms.Lookup(compressedSegName, 0)
+ newSym.P = s1
+ newSym.Size = int64(len(s1))
+ newSym.Sect = sect
+ newDwarfp = append(newDwarfp, newSym)
+ }
+ start = i + 1
+ }
+ }
+ dwarfp = newDwarfp
+
+ // Re-compute the locations of the compressed DWARF symbols
+ // and sections, since the layout of these within the file is
+ // based on Section.Vaddr and Symbol.Value.
+ pos := Segdwarf.Vaddr
+ var prevSect *sym.Section
+ for _, s := range dwarfp {
+ s.Value = int64(pos)
+ if s.Sect != prevSect {
+ s.Sect.Vaddr = uint64(s.Value)
+ prevSect = s.Sect
+ }
+ if s.Sub != nil {
+ log.Fatalf("%s: unexpected sub-symbols", s)
+ }
+ pos += uint64(s.Size)
+ if ctxt.HeadType == objabi.Hwindows {
+ pos = uint64(Rnd(int64(pos), PEFILEALIGN))
+ }
+
+ }
+ Segdwarf.Length = pos - Segdwarf.Vaddr
+}
diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go
index 60d387c193..877e4bfd5f 100644
--- a/src/cmd/link/internal/ld/elf.go
+++ b/src/cmd/link/internal/ld/elf.go
@@ -1261,7 +1261,7 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr {
sh.flags |= SHF_TLS
sh.type_ = SHT_NOBITS
}
- if strings.HasPrefix(sect.Name, ".debug") {
+ if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") {
sh.flags = 0
}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index 0d18a9fe1e..6cd4f47709 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1222,6 +1222,11 @@ func (ctxt *Link) hostlink() {
argv = append(argv, "-Qunused-arguments")
}
+ const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
+ if ctxt.compressDWARF && linkerFlagSupported(argv[0], compressDWARF) {
+ argv = append(argv, compressDWARF)
+ }
+
argv = append(argv, filepath.Join(*flagTmpdir, "go.o"))
argv = append(argv, hostobjCopy()...)
@@ -1268,21 +1273,9 @@ func (ctxt *Link) hostlink() {
// issue #17847. To avoid this problem pass -no-pie to the
// toolchain if it is supported.
if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
- src := filepath.Join(*flagTmpdir, "trivial.c")
- if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
- Errorf(nil, "WriteFile trivial.c failed: %v", err)
- }
-
// GCC uses -no-pie, clang uses -nopie.
for _, nopie := range []string{"-no-pie", "-nopie"} {
- cmd := exec.Command(argv[0], nopie, "trivial.c")
- cmd.Dir = *flagTmpdir
- cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
- out, err := cmd.CombinedOutput()
- // GCC says "unrecognized command line option ‘-no-pie’"
- // clang says "unknown argument: '-no-pie'"
- supported := err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
- if supported {
+ if linkerFlagSupported(argv[0], nopie) {
argv = append(argv, nopie)
break
}
@@ -1344,7 +1337,7 @@ func (ctxt *Link) hostlink() {
}
// For os.Rename to work reliably, must be in same directory as outfile.
combinedOutput := *flagOutfile + "~"
- isIOS, err := machoCombineDwarf(*flagOutfile, dsym, combinedOutput, ctxt.BuildMode)
+ isIOS, err := machoCombineDwarf(ctxt, *flagOutfile, dsym, combinedOutput)
if err != nil {
Exitf("%s: combining dwarf failed: %v", os.Args[0], err)
}
@@ -1357,6 +1350,25 @@ func (ctxt *Link) hostlink() {
}
}
+var createTrivialCOnce sync.Once
+
+func linkerFlagSupported(linker, flag string) bool {
+ createTrivialCOnce.Do(func() {
+ src := filepath.Join(*flagTmpdir, "trivial.c")
+ if err := ioutil.WriteFile(src, []byte("int main() { return 0; }"), 0666); err != nil {
+ Errorf(nil, "WriteFile trivial.c failed: %v", err)
+ }
+ })
+
+ cmd := exec.Command(linker, flag, "trivial.c")
+ cmd.Dir = *flagTmpdir
+ cmd.Env = append([]string{"LC_ALL=C"}, os.Environ()...)
+ out, err := cmd.CombinedOutput()
+ // GCC says "unrecognized command line option ‘-no-pie’"
+ // clang says "unknown argument: '-no-pie'"
+ return err == nil && !bytes.Contains(out, []byte("unrecognized")) && !bytes.Contains(out, []byte("unknown"))
+}
+
// hostlinkArchArgs returns arguments to pass to the external linker
// based on the architecture.
func hostlinkArchArgs(arch *sys.Arch) []string {
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index a790fd084b..2e66cf857c 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -63,9 +63,10 @@ type Link struct {
IsELF bool
HeadType objabi.HeadType
- linkShared bool // link against installed Go shared libraries
- LinkMode LinkMode
- BuildMode BuildMode
+ linkShared bool // link against installed Go shared libraries
+ LinkMode LinkMode
+ BuildMode BuildMode
+ compressDWARF bool
Tlsg *sym.Symbol
Libdir []string
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index d804dc83b3..8315de5152 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -103,32 +103,57 @@ const (
)
const (
- LC_SEGMENT = 0x1
- LC_SYMTAB = 0x2
- LC_UNIXTHREAD = 0x5
- LC_DYSYMTAB = 0xb
- LC_LOAD_DYLIB = 0xc
- LC_ID_DYLIB = 0xd
- LC_LOAD_DYLINKER = 0xe
- LC_PREBOUND_DYLIB = 0x10
- LC_LOAD_WEAK_DYLIB = 0x18
- LC_SEGMENT_64 = 0x19
- LC_UUID = 0x1b
- LC_RPATH = 0x8000001c
- LC_CODE_SIGNATURE = 0x1d
- LC_SEGMENT_SPLIT_INFO = 0x1e
- LC_REEXPORT_DYLIB = 0x8000001f
- LC_ENCRYPTION_INFO = 0x21
- LC_DYLD_INFO = 0x22
- LC_DYLD_INFO_ONLY = 0x80000022
- LC_VERSION_MIN_MACOSX = 0x24
- LC_VERSION_MIN_IPHONEOS = 0x25
- LC_FUNCTION_STARTS = 0x26
- LC_MAIN = 0x80000028
- LC_DATA_IN_CODE = 0x29
- LC_SOURCE_VERSION = 0x2A
- LC_DYLIB_CODE_SIGN_DRS = 0x2B
- LC_ENCRYPTION_INFO_64 = 0x2C
+ LC_SEGMENT = 0x1
+ LC_SYMTAB = 0x2
+ LC_SYMSEG = 0x3
+ LC_THREAD = 0x4
+ LC_UNIXTHREAD = 0x5
+ LC_LOADFVMLIB = 0x6
+ LC_IDFVMLIB = 0x7
+ LC_IDENT = 0x8
+ LC_FVMFILE = 0x9
+ LC_PREPAGE = 0xa
+ LC_DYSYMTAB = 0xb
+ LC_LOAD_DYLIB = 0xc
+ LC_ID_DYLIB = 0xd
+ LC_LOAD_DYLINKER = 0xe
+ LC_ID_DYLINKER = 0xf
+ LC_PREBOUND_DYLIB = 0x10
+ LC_ROUTINES = 0x11
+ LC_SUB_FRAMEWORK = 0x12
+ LC_SUB_UMBRELLA = 0x13
+ LC_SUB_CLIENT = 0x14
+ LC_SUB_LIBRARY = 0x15
+ LC_TWOLEVEL_HINTS = 0x16
+ LC_PREBIND_CKSUM = 0x17
+ LC_LOAD_WEAK_DYLIB = 0x18
+ LC_SEGMENT_64 = 0x19
+ LC_ROUTINES_64 = 0x1a
+ LC_UUID = 0x1b
+ LC_RPATH = 0x8000001c
+ LC_CODE_SIGNATURE = 0x1d
+ LC_SEGMENT_SPLIT_INFO = 0x1e
+ LC_REEXPORT_DYLIB = 0x8000001f
+ LC_LAZY_LOAD_DYLIB = 0x20
+ LC_ENCRYPTION_INFO = 0x21
+ LC_DYLD_INFO = 0x22
+ LC_DYLD_INFO_ONLY = 0x80000022
+ LC_LOAD_UPWARD_DYLIB = 0x80000023
+ LC_VERSION_MIN_MACOSX = 0x24
+ LC_VERSION_MIN_IPHONEOS = 0x25
+ LC_FUNCTION_STARTS = 0x26
+ LC_DYLD_ENVIRONMENT = 0x27
+ LC_MAIN = 0x80000028
+ LC_DATA_IN_CODE = 0x29
+ LC_SOURCE_VERSION = 0x2A
+ LC_DYLIB_CODE_SIGN_DRS = 0x2B
+ LC_ENCRYPTION_INFO_64 = 0x2C
+ LC_LINKER_OPTION = 0x2D
+ LC_LINKER_OPTIMIZATION_HINT = 0x2E
+ LC_VERSION_MIN_TVOS = 0x2F
+ LC_VERSION_MIN_WATCHOS = 0x30
+ LC_VERSION_NOTE = 0x31
+ LC_BUILD_VERSION = 0x32
)
const (
diff --git a/src/cmd/link/internal/ld/macho_combine_dwarf.go b/src/cmd/link/internal/ld/macho_combine_dwarf.go
index 82228faa8d..95bd4c7c36 100644
--- a/src/cmd/link/internal/ld/macho_combine_dwarf.go
+++ b/src/cmd/link/internal/ld/macho_combine_dwarf.go
@@ -6,6 +6,7 @@ package ld
import (
"bytes"
+ "compress/zlib"
"debug/macho"
"encoding/binary"
"fmt"
@@ -93,7 +94,7 @@ func (r loadCmdReader) WriteAt(offset int64, data interface{}) error {
// header to add the DWARF sections. (Use ld's -headerpad option)
// dsym is the path to the macho file containing DWARF from dsymutil.
// outexe is the path where the combined executable should be saved.
-func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, error) {
+func machoCombineDwarf(ctxt *Link, inexe, dsym, outexe string) (bool, error) {
exef, err := os.Open(inexe)
if err != nil {
return false, err
@@ -156,6 +157,13 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, e
return false, fmt.Errorf("missing __DWARF segment")
}
+ // Try to compress the DWARF sections. This includes some Apple
+ // proprietary sections like __apple_types.
+ compressedSects, compressedBytes, err := machoCompressSections(ctxt, dwarfm)
+ if err != nil {
+ return false, err
+ }
+
// Now copy the dwarf data into the output.
// Kernel requires all loaded segments to be page-aligned in the file,
// even though we mark this one as being 0 bytes of virtual address space.
@@ -168,15 +176,27 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, e
if _, err = dwarff.Seek(int64(realdwarf.Offset), 0); err != nil {
return false, err
}
- if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
- return false, err
+
+ // Write out the compressed sections, or the originals if we gave up
+ // on compressing them.
+ var dwarfsize uint64
+ if compressedBytes != nil {
+ dwarfsize = uint64(len(compressedBytes))
+ if _, err := outf.Write(compressedBytes); err != nil {
+ return false, err
+ }
+ } else {
+ if _, err := io.CopyN(outf, dwarff, int64(realdwarf.Filesz)); err != nil {
+ return false, err
+ }
+ dwarfsize = realdwarf.Filesz
}
// And finally the linkedit section.
if _, err = exef.Seek(int64(linkseg.Offset), 0); err != nil {
return false, err
}
- linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+realdwarf.Filesz, pageAlign)
+ linkstart = machoCalcStart(linkseg.Offset, uint64(dwarfstart)+dwarfsize, pageAlign)
linkoffset = uint32(linkstart - int64(linkseg.Offset))
if _, err = outf.Seek(linkstart, 0); err != nil {
return false, err
@@ -196,14 +216,14 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, e
if availablePadding < int64(realdwarf.Len) {
return false, fmt.Errorf("No room to add dwarf info. Need at least %d padding bytes, found %d", realdwarf.Len, availablePadding)
}
- // First, copy the dwarf load command into the header
+ // First, copy the dwarf load command into the header. It will be
+ // updated later with new offsets and lengths as necessary.
if _, err = outf.Seek(dwarfCmdOffset, 0); err != nil {
return false, err
}
if _, err := io.CopyN(outf, bytes.NewReader(realdwarf.Raw()), int64(realdwarf.Len)); err != nil {
return false, err
}
-
if _, err = outf.Seek(int64(unsafe.Offsetof(exem.FileHeader.Ncmd)), 0); err != nil {
return false, err
}
@@ -235,7 +255,7 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, e
err = machoUpdateLoadCommand(reader, &linkEditDataCmd{}, "DataOff")
case LC_ENCRYPTION_INFO, LC_ENCRYPTION_INFO_64:
err = machoUpdateLoadCommand(reader, &encryptionInfoCmd{}, "CryptOff")
- case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB:
+ case macho.LoadCmdDylib, macho.LoadCmdThread, macho.LoadCmdUnixThread, LC_PREBOUND_DYLIB, LC_UUID, LC_VERSION_MIN_MACOSX, LC_VERSION_MIN_IPHONEOS, LC_SOURCE_VERSION, LC_MAIN, LC_LOAD_DYLINKER, LC_LOAD_WEAK_DYLIB, LC_REEXPORT_DYLIB, LC_RPATH, LC_ID_DYLIB, LC_SYMSEG, LC_LOADFVMLIB, LC_IDFVMLIB, LC_IDENT, LC_FVMFILE, LC_PREPAGE, LC_ID_DYLINKER, LC_ROUTINES, LC_SUB_FRAMEWORK, LC_SUB_UMBRELLA, LC_SUB_CLIENT, LC_SUB_LIBRARY, LC_TWOLEVEL_HINTS, LC_PREBIND_CKSUM, LC_ROUTINES_64, LC_LAZY_LOAD_DYLIB, LC_LOAD_UPWARD_DYLIB, LC_DYLD_ENVIRONMENT, LC_LINKER_OPTION, LC_LINKER_OPTIMIZATION_HINT, LC_VERSION_MIN_TVOS, LC_VERSION_MIN_WATCHOS, LC_VERSION_NOTE, LC_BUILD_VERSION:
// Nothing to update
default:
err = fmt.Errorf("Unknown load command 0x%x (%s)\n", int(cmd.Cmd), cmd.Cmd)
@@ -244,7 +264,76 @@ func machoCombineDwarf(inexe, dsym, outexe string, buildmode BuildMode) (bool, e
return false, err
}
}
- return false, machoUpdateDwarfHeader(&reader, buildmode)
+ // Do the final update of the DWARF segment's load command.
+ return false, machoUpdateDwarfHeader(&reader, ctxt.BuildMode, compressedSects)
+}
+
+// machoCompressSections tries to compress the DWARF segments in dwarfm,
+// returning the updated sections and segment contents, nils if the sections
+// weren't compressed, or an error if there was a problem reading dwarfm.
+func machoCompressSections(ctxt *Link, dwarfm *macho.File) ([]*macho.Section, []byte, error) {
+ if !ctxt.compressDWARF {
+ return nil, nil, nil
+ }
+
+ dwarfseg := dwarfm.Segment("__DWARF")
+ var sects []*macho.Section
+ var bytes []byte
+
+ for _, sect := range dwarfm.Sections {
+ if sect.Seg != "__DWARF" {
+ continue
+ }
+
+ // As of writing, there are no relocations in dsymutil's output
+ // so there's no point in worrying about them. Bail out if that
+ // changes.
+ if sect.Nreloc != 0 {
+ return nil, nil, nil
+ }
+
+ data, err := sect.Data()
+ if err != nil {
+ return nil, nil, err
+ }
+
+ compressed, contents, err := machoCompressSection(data)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ newSec := *sect
+ newSec.Offset = uint32(dwarfseg.Offset) + uint32(len(bytes))
+ newSec.Addr = dwarfseg.Addr + uint64(len(bytes))
+ if compressed {
+ newSec.Name = "__z" + sect.Name[2:]
+ newSec.Size = uint64(len(contents))
+ }
+ sects = append(sects, &newSec)
+ bytes = append(bytes, contents...)
+ }
+ return sects, bytes, nil
+}
+
+// machoCompressSection compresses secBytes if it results in less data.
+func machoCompressSection(sectBytes []byte) (compressed bool, contents []byte, err error) {
+ var buf bytes.Buffer
+ buf.Write([]byte("ZLIB"))
+ var sizeBytes [8]byte
+ binary.BigEndian.PutUint64(sizeBytes[:], uint64(len(sectBytes)))
+ buf.Write(sizeBytes[:])
+
+ z := zlib.NewWriter(&buf)
+ if _, err := z.Write(sectBytes); err != nil {
+ return false, nil, err
+ }
+ if err := z.Close(); err != nil {
+ return false, nil, err
+ }
+ if len(buf.Bytes()) >= len(sectBytes) {
+ return false, sectBytes, nil
+ }
+ return true, buf.Bytes(), nil
}
// machoUpdateSegment updates the load command for a moved segment.
@@ -267,10 +356,10 @@ func machoUpdateSegment(r loadCmdReader, seg, sect interface{}) error {
return err
}
// There shouldn't be any sections, but just to make sure...
- return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset), 0)
+ return machoUpdateSections(r, segValue, reflect.ValueOf(sect), uint64(linkoffset), 0, nil)
}
-func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset, deltaAddr uint64) error {
+func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset, deltaAddr uint64, compressedSects []*macho.Section) error {
iseg := reflect.Indirect(seg)
nsect := iseg.FieldByName("Nsect").Uint()
if nsect == 0 {
@@ -282,19 +371,35 @@ func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset,
offsetField := isect.FieldByName("Offset")
reloffField := isect.FieldByName("Reloff")
addrField := isect.FieldByName("Addr")
+ nameField := isect.FieldByName("Name")
+ sizeField := isect.FieldByName("Size")
sectSize := int64(isect.Type().Size())
for i := uint64(0); i < nsect; i++ {
if err := r.ReadAt(sectOffset, sect.Interface()); err != nil {
return err
}
- if offsetField.Uint() != 0 {
- offsetField.SetUint(offsetField.Uint() + deltaOffset)
- }
- if reloffField.Uint() != 0 {
- reloffField.SetUint(reloffField.Uint() + deltaOffset)
- }
- if addrField.Uint() != 0 {
- addrField.SetUint(addrField.Uint() + deltaAddr)
+ if compressedSects != nil {
+ cSect := compressedSects[i]
+ var name [16]byte
+ copy(name[:], []byte(cSect.Name))
+ nameField.Set(reflect.ValueOf(name))
+ sizeField.SetUint(cSect.Size)
+ if cSect.Offset != 0 {
+ offsetField.SetUint(uint64(cSect.Offset) + deltaOffset)
+ }
+ if cSect.Addr != 0 {
+ addrField.SetUint(cSect.Addr + deltaAddr)
+ }
+ } else {
+ if offsetField.Uint() != 0 {
+ offsetField.SetUint(offsetField.Uint() + deltaOffset)
+ }
+ if reloffField.Uint() != 0 {
+ reloffField.SetUint(reloffField.Uint() + deltaOffset)
+ }
+ if addrField.Uint() != 0 {
+ addrField.SetUint(addrField.Uint() + deltaAddr)
+ }
}
if err := r.WriteAt(sectOffset, sect.Interface()); err != nil {
return err
@@ -305,7 +410,7 @@ func machoUpdateSections(r loadCmdReader, seg, sect reflect.Value, deltaOffset,
}
// machoUpdateDwarfHeader updates the DWARF segment load command.
-func machoUpdateDwarfHeader(r *loadCmdReader, buildmode BuildMode) error {
+func machoUpdateDwarfHeader(r *loadCmdReader, buildmode BuildMode, compressedSects []*macho.Section) error {
var seg, sect interface{}
cmd, err := r.Next()
if err != nil {
@@ -322,10 +427,18 @@ func machoUpdateDwarfHeader(r *loadCmdReader, buildmode BuildMode) error {
return err
}
segv := reflect.ValueOf(seg).Elem()
-
segv.FieldByName("Offset").SetUint(uint64(dwarfstart))
segv.FieldByName("Addr").SetUint(uint64(dwarfaddr))
+ if compressedSects != nil {
+ var segSize uint64
+ for _, newSect := range compressedSects {
+ segSize += newSect.Size
+ }
+ segv.FieldByName("Filesz").SetUint(segSize)
+ segv.FieldByName("Memsz").SetUint(uint64(Rnd(int64(segSize), 1<<pageAlign)))
+ }
+
deltaOffset := uint64(dwarfstart) - realdwarf.Offset
deltaAddr := uint64(dwarfaddr) - realdwarf.Addr
@@ -344,7 +457,7 @@ func machoUpdateDwarfHeader(r *loadCmdReader, buildmode BuildMode) error {
if err := r.WriteAt(0, seg); err != nil {
return err
}
- return machoUpdateSections(*r, segv, reflect.ValueOf(sect), deltaOffset, deltaAddr)
+ return machoUpdateSections(*r, segv, reflect.ValueOf(sect), deltaOffset, deltaAddr, compressedSects)
}
func machoUpdateLoadCommand(r loadCmdReader, cmd interface{}, fields ...string) error {
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index bfa3f70a9e..d7929d59fd 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -122,6 +122,7 @@ func Main(arch *sys.Arch, theArch Arch) {
flag.BoolVar(&ctxt.linkShared, "linkshared", false, "link against installed Go shared libraries")
flag.Var(&ctxt.LinkMode, "linkmode", "set link `mode`")
flag.Var(&ctxt.BuildMode, "buildmode", "set build `mode`")
+ flag.BoolVar(&ctxt.compressDWARF, "compressdwarf", true, "compress DWARF if possible")
objabi.Flagfn1("B", "add an ELF NT_GNU_BUILD_ID `note` when using ELF", addbuildinfo)
objabi.Flagfn1("L", "add specified `directory` to library path", func(a string) { Lflag(ctxt, a) })
objabi.AddVersionFlag() // -V
@@ -224,8 +225,10 @@ func Main(arch *sys.Arch, theArch Arch) {
ctxt.typelink()
ctxt.symtab()
ctxt.dodata()
- ctxt.address()
+ order := ctxt.address()
ctxt.reloc()
+ dwarfcompress(ctxt)
+ ctxt.layout(order)
thearch.Asmb(ctxt)
ctxt.undef()
ctxt.hostlink()
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 50ac6d0743..7b7f7068e7 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -11,6 +11,7 @@ import (
"log"
"os"
"path/filepath"
+ "strings"
)
// iteration over encoded pcdata tables.
@@ -159,13 +160,15 @@ func renumberfiles(ctxt *Link, files []*sym.Symbol, d *sym.Pcdata) {
*d = out
}
-// onlycsymbol reports whether this is a cgo symbol provided by the
-// runtime and only used from C code.
+// onlycsymbol reports whether this is a symbol that is referenced by C code.
func onlycsymbol(s *sym.Symbol) bool {
switch s.Name {
case "_cgo_topofstack", "_cgo_panic", "crosscall2":
return true
}
+ if strings.HasPrefix(s.Name, "_cgoexp_") {
+ return true
+ }
return false
}
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 8005dc5228..85acb7a11b 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -395,6 +395,7 @@ type peFile struct {
sections []*peSection
stringTable peStringTable
textSect *peSection
+ rdataSect *peSection
dataSect *peSection
bssSect *peSection
ctorsSect *peSection
@@ -548,21 +549,24 @@ func (f *peFile) emitRelocations(ctxt *Link) {
return relocs
}
- f.textSect.emitRelocations(ctxt.Out, func() int {
- n := relocsect(Segtext.Sections[0], ctxt.Textp, Segtext.Vaddr)
- for _, sect := range Segtext.Sections[1:] {
- n += relocsect(sect, datap, Segtext.Vaddr)
- }
- return n
- })
-
- f.dataSect.emitRelocations(ctxt.Out, func() int {
- var n int
- for _, sect := range Segdata.Sections {
- n += relocsect(sect, datap, Segdata.Vaddr)
- }
- return n
- })
+ sects := []struct {
+ peSect *peSection
+ seg *sym.Segment
+ syms []*sym.Symbol
+ }{
+ {f.textSect, &Segtext, ctxt.Textp},
+ {f.rdataSect, &Segrodata, datap},
+ {f.dataSect, &Segdata, datap},
+ }
+ for _, s := range sects {
+ s.peSect.emitRelocations(ctxt.Out, func() int {
+ var n int
+ for _, sect := range s.seg.Sections {
+ n += relocsect(sect, s.syms, s.seg.Vaddr)
+ }
+ return n
+ })
+ }
dwarfLoop:
for _, sect := range Segdwarf.Sections {
@@ -622,8 +626,11 @@ func (f *peFile) mapToPESection(s *sym.Symbol, linkmode LinkMode) (pesectidx int
if s.Sect.Seg == &Segtext {
return f.textSect.index, int64(uint64(s.Value) - Segtext.Vaddr), nil
}
+ if s.Sect.Seg == &Segrodata {
+ return f.rdataSect.index, int64(uint64(s.Value) - Segrodata.Vaddr), nil
+ }
if s.Sect.Seg != &Segdata {
- return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .data section", s.Name)
+ return 0, 0, fmt.Errorf("could not map %s symbol with non .text or .rdata or .data section", s.Name)
}
v := uint64(s.Value) - Segdata.Vaddr
if linkmode != LinkExternal {
@@ -904,7 +911,11 @@ func Peinit(ctxt *Link) {
}
if ctxt.LinkMode == LinkExternal {
- PESECTALIGN = 0
+ // .rdata section will contain "masks" and "shifts" symbols, and they
+ // need to be aligned to 16-bytes. So make all sections aligned
+ // to 32-byte and mark them all IMAGE_SCN_ALIGN_32BYTES so external
+ // linker will honour that requirement.
+ PESECTALIGN = 32
PEFILEALIGN = 0
}
@@ -1325,6 +1336,19 @@ func Asmbpe(ctxt *Link) {
t.checkSegment(&Segtext)
pefile.textSect = t
+ ro := pefile.addSection(".rdata", int(Segrodata.Length), int(Segrodata.Length))
+ ro.characteristics = IMAGE_SCN_CNT_INITIALIZED_DATA | IMAGE_SCN_MEM_READ
+ if ctxt.LinkMode == LinkExternal {
+ // some data symbols (e.g. masks) end up in the .rdata section, and they normally
+ // expect larger alignment requirement than the default text section alignment.
+ ro.characteristics |= IMAGE_SCN_ALIGN_32BYTES
+ } else {
+ // TODO(brainman): should not need IMAGE_SCN_MEM_EXECUTE, but I do not know why it carshes without it
+ ro.characteristics |= IMAGE_SCN_MEM_EXECUTE
+ }
+ ro.checkSegment(&Segrodata)
+ pefile.rdataSect = ro
+
var d *peSection
if ctxt.LinkMode != LinkExternal {
d = pefile.addSection(".data", int(Segdata.Length), int(Segdata.Filelen))
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index bb8c1992ba..88d476710b 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -368,28 +368,30 @@ func (ctxt *Link) symtab() {
// pseudo-symbols to mark locations of type, string, and go string data.
var symtype *sym.Symbol
var symtyperel *sym.Symbol
- if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
- s = ctxt.Syms.Lookup("type.*", 0)
+ if !ctxt.DynlinkingGo() {
+ if ctxt.UseRelro() && (ctxt.BuildMode == BuildModeCArchive || ctxt.BuildMode == BuildModeCShared || ctxt.BuildMode == BuildModePIE) {
+ s = ctxt.Syms.Lookup("type.*", 0)
- s.Type = sym.STYPE
- s.Size = 0
- s.Attr |= sym.AttrReachable
- symtype = s
+ s.Type = sym.STYPE
+ s.Size = 0
+ s.Attr |= sym.AttrReachable
+ symtype = s
- s = ctxt.Syms.Lookup("typerel.*", 0)
+ s = ctxt.Syms.Lookup("typerel.*", 0)
- s.Type = sym.STYPERELRO
- s.Size = 0
- s.Attr |= sym.AttrReachable
- symtyperel = s
- } else if !ctxt.DynlinkingGo() {
- s = ctxt.Syms.Lookup("type.*", 0)
+ s.Type = sym.STYPERELRO
+ s.Size = 0
+ s.Attr |= sym.AttrReachable
+ symtyperel = s
+ } else {
+ s = ctxt.Syms.Lookup("type.*", 0)
- s.Type = sym.STYPE
- s.Size = 0
- s.Attr |= sym.AttrReachable
- symtype = s
- symtyperel = s
+ s.Type = sym.STYPE
+ s.Size = 0
+ s.Attr |= sym.AttrReachable
+ symtype = s
+ symtyperel = s
+ }
}
groupSym := func(name string, t sym.SymKind) *sym.Symbol {
diff --git a/src/cmd/link/internal/wasm/asm.go b/src/cmd/link/internal/wasm/asm.go
index aadb0c3b6e..7cc6bef6b7 100644
--- a/src/cmd/link/internal/wasm/asm.go
+++ b/src/cmd/link/internal/wasm/asm.go
@@ -122,6 +122,7 @@ func asmb(ctxt *ld.Link) {
}
// collect functions with WebAssembly body
+ var buildid []byte
fns := make([]*wasmFunc, len(ctxt.Textp))
for i, fn := range ctxt.Textp {
wfn := new(bytes.Buffer)
@@ -129,7 +130,7 @@ func asmb(ctxt *ld.Link) {
writeUleb128(wfn, 0) // number of sets of locals
writeI32Const(wfn, 0)
wfn.WriteByte(0x0b) // end
-
+ buildid = fn.P
} else {
// Relocations have variable length, handle them here.
off := int32(0)
@@ -166,6 +167,11 @@ func asmb(ctxt *ld.Link) {
ctxt.Out.Write([]byte{0x00, 0x61, 0x73, 0x6d}) // magic
ctxt.Out.Write([]byte{0x01, 0x00, 0x00, 0x00}) // version
+ // Add any buildid early in the binary:
+ if len(buildid) != 0 {
+ writeBuildID(ctxt, buildid)
+ }
+
writeTypeSec(ctxt, types)
writeImportSec(ctxt, hostImports)
writeFunctionSec(ctxt, fns)
@@ -177,7 +183,7 @@ func asmb(ctxt *ld.Link) {
writeCodeSec(ctxt, fns)
writeDataSec(ctxt)
if !*ld.FlagS {
- writeNameSec(ctxt, append(hostImports, fns...))
+ writeNameSec(ctxt, len(hostImports), fns)
}
ctxt.Out.Flush()
@@ -207,6 +213,13 @@ func writeSecSize(ctxt *ld.Link, sizeOffset int64) {
ctxt.Out.SeekSet(endOffset)
}
+func writeBuildID(ctxt *ld.Link, buildid []byte) {
+ sizeOffset := writeSecHeader(ctxt, sectionCustom)
+ writeName(ctxt.Out, "go.buildid")
+ ctxt.Out.Write(buildid)
+ writeSecSize(ctxt, sizeOffset)
+}
+
// writeTypeSec writes the section that declares all function types
// so they can be referenced by index.
func writeTypeSec(ctxt *ld.Link, types []*wasmFuncType) {
@@ -304,6 +317,7 @@ func writeGlobalSec(ctxt *ld.Link) {
I64, // 6: RET1
I64, // 7: RET2
I64, // 8: RET3
+ I32, // 9: RUN
}
writeUleb128(ctxt.Out, uint64(len(globalRegs))) // number of globals
@@ -408,14 +422,14 @@ var nameRegexp = regexp.MustCompile(`[^\w\.]`)
// writeNameSec writes an optional section that assigns names to the functions declared by the "func" section.
// The names are only used by WebAssembly stack traces, debuggers and decompilers.
// TODO(neelance): add symbol table of DATA symbols
-func writeNameSec(ctxt *ld.Link, fns []*wasmFunc) {
+func writeNameSec(ctxt *ld.Link, firstFnIndex int, fns []*wasmFunc) {
sizeOffset := writeSecHeader(ctxt, sectionCustom)
writeName(ctxt.Out, "name")
sizeOffset2 := writeSecHeader(ctxt, 0x01) // function names
writeUleb128(ctxt.Out, uint64(len(fns)))
for i, fn := range fns {
- writeUleb128(ctxt.Out, uint64(i))
+ writeUleb128(ctxt.Out, uint64(firstFnIndex+i))
writeName(ctxt.Out, fn.Name)
}
writeSecSize(ctxt, sizeOffset2)
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index 4be5d0e74e..ccf5682d69 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -126,6 +126,15 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
names["main."+f[0]] = f[1]
}
+ runtimeSyms := map[string]string{
+ "runtime.text": "T",
+ "runtime.etext": "T",
+ "runtime.rodata": "R",
+ "runtime.erodata": "R",
+ "runtime.epclntab": "R",
+ "runtime.noptrdata": "D",
+ }
+
out, err = exec.Command(testnmpath, exe).CombinedOutput()
if err != nil {
t.Fatalf("go tool nm: %v\n%s", err, string(out))
@@ -147,6 +156,16 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
if _, found := dups[name]; found {
t.Errorf("duplicate name of %q is found", name)
}
+ if stype, found := runtimeSyms[name]; found {
+ if runtime.GOOS == "plan9" && stype == "R" {
+ // no read-only data segment symbol on Plan 9
+ stype = "D"
+ }
+ if want, have := stype, strings.ToUpper(f[1]); have != want {
+ t.Errorf("want %s type for %s symbol, but have %s", want, name, have)
+ }
+ delete(runtimeSyms, name)
+ }
}
err = scanner.Err()
if err != nil {
@@ -155,6 +174,9 @@ func testGoExec(t *testing.T, iscgo, isexternallinker bool) {
if len(names) > 0 {
t.Errorf("executable is missing %v symbols", names)
}
+ if len(runtimeSyms) > 0 {
+ t.Errorf("executable is missing %v symbols", runtimeSyms)
+ }
}
func TestGoExec(t *testing.T) {
diff --git a/src/cmd/trace/annotations.go b/src/cmd/trace/annotations.go
index c91f18ef6f..96c109e0f2 100644
--- a/src/cmd/trace/annotations.go
+++ b/src/cmd/trace/annotations.go
@@ -1,3 +1,7 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
package main
import (
diff --git a/src/cmd/trace/annotations_test.go b/src/cmd/trace/annotations_test.go
index 5d2b226b35..a9068d53c1 100644
--- a/src/cmd/trace/annotations_test.go
+++ b/src/cmd/trace/annotations_test.go
@@ -1,3 +1,9 @@
+// Copyright 2018 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 !js
+
package main
import (
diff --git a/src/cmd/trace/trace_test.go b/src/cmd/trace/trace_test.go
index 852d745b29..9e90f50d4b 100644
--- a/src/cmd/trace/trace_test.go
+++ b/src/cmd/trace/trace_test.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build !js
+
package main
import (
diff --git a/src/cmd/vet/all/main.go b/src/cmd/vet/all/main.go
index 6c56daff03..09181f9689 100644
--- a/src/cmd/vet/all/main.go
+++ b/src/cmd/vet/all/main.go
@@ -192,9 +192,9 @@ func vetPlatforms(pp []platform) {
}
func (p platform) vet() {
- if p.os == "js" && p.arch == "wasm" {
- // TODO(neelance): enable as soon as js/wasm has fully landed
- fmt.Println("skipping js/wasm")
+ if p.os == "linux" && p.arch == "riscv64" {
+ // TODO(tklauser): enable as soon as the riscv64 port has fully landed
+ fmt.Println("skipping linux/riscv64")
return
}
diff --git a/src/cmd/vet/all/whitelist/darwin_386.txt b/src/cmd/vet/all/whitelist/darwin_386.txt
index 934b773f50..5c25e092f2 100644
--- a/src/cmd/vet/all/whitelist/darwin_386.txt
+++ b/src/cmd/vet/all/whitelist/darwin_386.txt
@@ -2,5 +2,4 @@
// Ok
-runtime/sys_darwin_386.s: [386] sysenter: function sysenter missing Go declaration
runtime/sys_darwin_386.s: [386] setldt: function setldt missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/darwin_arm.txt b/src/cmd/vet/all/whitelist/darwin_arm.txt
index 8e935b6ff2..1c25c6a939 100644
--- a/src/cmd/vet/all/whitelist/darwin_arm.txt
+++ b/src/cmd/vet/all/whitelist/darwin_arm.txt
@@ -1,11 +1,5 @@
// darwin/arm-specific vet whitelist. See readme.txt for details.
-// False positives due to comments in assembly.
-// To be removed. See CL 27154.
-
-runtime/sys_darwin_arm.s: [arm] sigfwd: use of unnamed argument 0(FP); offset 0 is fn+0(FP)
-
-
// Ok.
runtime/asm_arm.s: [arm] sigreturn: function sigreturn missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/darwin_arm64.txt b/src/cmd/vet/all/whitelist/darwin_arm64.txt
index 8cab997961..a1edb71383 100644
--- a/src/cmd/vet/all/whitelist/darwin_arm64.txt
+++ b/src/cmd/vet/all/whitelist/darwin_arm64.txt
@@ -1,5 +1,3 @@
// darwin/arm64-specific vet whitelist. See readme.txt for details.
-runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
-runtime/sys_darwin_arm64.s: [arm64] sigtramp: 24(RSP) should be infostyle+8(FP)
runtime/asm_arm64.s: [arm64] sigreturn: function sigreturn missing Go declaration
diff --git a/src/cmd/vet/all/whitelist/linux_ppc64x.txt b/src/cmd/vet/all/whitelist/linux_ppc64x.txt
index 21e87e37d8..0091d97110 100644
--- a/src/cmd/vet/all/whitelist/linux_ppc64x.txt
+++ b/src/cmd/vet/all/whitelist/linux_ppc64x.txt
@@ -2,4 +2,3 @@
runtime/sys_linux_ppc64x.s: [GOARCH] _sigtramp: function _sigtramp missing Go declaration
runtime/sys_linux_ppc64x.s: [GOARCH] _cgoSigtramp: function _cgoSigtramp missing Go declaration
-runtime/asm_ppc64x.s: [GOARCH] procyield: use of 24(R1) points beyond argument frame
diff --git a/src/cmd/vet/all/whitelist/s390x.txt b/src/cmd/vet/all/whitelist/s390x.txt
index 9fa4949575..5bc48e5afc 100644
--- a/src/cmd/vet/all/whitelist/s390x.txt
+++ b/src/cmd/vet/all/whitelist/s390x.txt
@@ -5,3 +5,10 @@ runtime/memclr_s390x.s: [s390x] memclr_s390x_exrl_xc: function memclr_s390x_exrl
runtime/memmove_s390x.s: [s390x] memmove_s390x_exrl_mvc: function memmove_s390x_exrl_mvc missing Go declaration
runtime/tls_s390x.s: [s390x] save_g: function save_g missing Go declaration
runtime/tls_s390x.s: [s390x] load_g: function load_g missing Go declaration
+internal/cpu/cpu_s390x.s: [s390x] stfle: invalid MOVD of ret+0(FP); cpu.facilityList is 32-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmcQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmctrQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kmaQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] kimdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
+internal/cpu/cpu_s390x.s: [s390x] klmdQuery: invalid MOVD of ret+0(FP); cpu.queryResult is 16-byte value
diff --git a/src/cmd/vet/all/whitelist/wasm.txt b/src/cmd/vet/all/whitelist/wasm.txt
new file mode 100644
index 0000000000..7a8037f085
--- /dev/null
+++ b/src/cmd/vet/all/whitelist/wasm.txt
@@ -0,0 +1,28 @@
+// wasm-specific vet whitelist. See readme.txt for details.
+
+// False positives.
+
+// Nothing much to do about cross-package assembly. Unfortunate.
+internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: Compare is in package bytes
+internal/bytealg/compare_wasm.s: [wasm] cannot check cross-package assembly function: cmpstring is in package runtime
+
+// morestack intentionally omits arg size.
+runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame
+runtime/asm_wasm.s: [wasm] morestack: use of 16(SP) points beyond argument frame
+runtime/asm_wasm.s: [wasm] morestack: use of 8(SP) points beyond argument frame
+
+// rt0_go does not allocate a stack frame.
+runtime/asm_wasm.s: [wasm] rt0_go: use of 8(SP) points beyond argument frame
+
+// Calling WebAssembly import. No write from Go assembly.
+runtime/sys_wasm.s: [wasm] nanotime: RET without writing to 8-byte ret+0(FP)
+runtime/sys_wasm.s: [wasm] scheduleCallback: RET without writing to 4-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] stringVal: RET without writing to 8-byte ret+16(FP)
+syscall/js/js_js.s: [wasm] valueGet: RET without writing to 8-byte ret+24(FP)
+syscall/js/js_js.s: [wasm] valueIndex: RET without writing to 8-byte ret+16(FP)
+syscall/js/js_js.s: [wasm] valueCall: RET without writing to 8-byte ret+48(FP)
+syscall/js/js_js.s: [wasm] valueInvoke: RET without writing to 8-byte ret+32(FP)
+syscall/js/js_js.s: [wasm] valueNew: RET without writing to 8-byte ret+32(FP)
+syscall/js/js_js.s: [wasm] valueLength: RET without writing to 8-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] valuePrepareString: RET without writing to 8-byte ret+8(FP)
+syscall/js/js_js.s: [wasm] valueInstanceOf: RET without writing to 1-byte ret+16(FP)
diff --git a/src/cmd/vet/asmdecl.go b/src/cmd/vet/asmdecl.go
index d3335c69f5..ccf6269f1d 100644
--- a/src/cmd/vet/asmdecl.go
+++ b/src/cmd/vet/asmdecl.go
@@ -77,6 +77,7 @@ var (
asmArchPpc64 = asmArch{name: "ppc64", bigEndian: true, stack: "R1", lr: true}
asmArchPpc64LE = asmArch{name: "ppc64le", bigEndian: false, stack: "R1", lr: true}
asmArchS390X = asmArch{name: "s390x", bigEndian: true, stack: "R15", lr: true}
+ asmArchWasm = asmArch{name: "wasm", bigEndian: false, stack: "SP", lr: false}
arches = []*asmArch{
&asmArch386,
@@ -91,6 +92,7 @@ var (
&asmArchPpc64,
&asmArchPpc64LE,
&asmArchS390X,
+ &asmArchWasm,
}
)
@@ -104,6 +106,8 @@ func init() {
arch.ptrSize = int(arch.sizes.Sizeof(types.Typ[types.UnsafePointer]))
arch.maxAlign = int(arch.sizes.Alignof(types.Typ[types.Int64]))
}
+
+ registerPkgCheck("asmdecl", asmCheck)
}
var (
@@ -119,7 +123,7 @@ var (
)
func asmCheck(pkg *Package) {
- if !vet("asmdecl") {
+ if vcfg.VetxOnly {
return
}
diff --git a/src/cmd/vet/bool.go b/src/cmd/vet/bool.go
index e8b73175aa..1cd477f988 100644
--- a/src/cmd/vet/bool.go
+++ b/src/cmd/vet/bool.go
@@ -9,7 +9,6 @@ package main
import (
"go/ast"
"go/token"
- "go/types"
)
func init() {
@@ -142,28 +141,22 @@ func hasSideEffects(f *File, e ast.Expr) bool {
ast.Inspect(e, func(node ast.Node) bool {
switch n := node.(type) {
case *ast.CallExpr:
- // Don't call Type.Underlying(), since its lack
- // lets us see the NamedFuncType(x) type
- // conversion as a *types.Named.
typVal := f.pkg.types[n.Fun]
- _, isSig := typVal.Type.(*types.Signature)
switch {
- case typVal.IsValue() && isSig:
- // If we have a value of unnamed signature type,
- // this CallExpr is a non-builtin func call and
- // not a type conversion. Conservatively assume
- // that all function and method calls have side
- // effects for now.
+ case typVal.IsType():
+ // Type conversion, which is safe.
+ case typVal.IsBuiltin():
+ // Builtin func, conservatively assumed to not
+ // be safe for now.
safe = false
return false
- case typVal.IsBuiltin():
- // For now, conservatively assume that all
- // built-in functions have side effects.
+ default:
+ // A non-builtin func or method call.
+ // Conservatively assume that all of them have
+ // side effects for now.
safe = false
return false
}
- // It's a type conversion, which cannot
- // have side effects.
case *ast.UnaryExpr:
if n.Op == token.ARROW {
safe = false
diff --git a/src/cmd/vet/buildtag.go b/src/cmd/vet/buildtag.go
index d1fedec554..ba3a361b91 100644
--- a/src/cmd/vet/buildtag.go
+++ b/src/cmd/vet/buildtag.go
@@ -18,18 +18,17 @@ var (
plusBuild = []byte("+build")
)
+func badfLine(f *File, line int, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg)
+ setExit(1)
+}
+
// checkBuildTag checks that build tags are in the correct location and well-formed.
func checkBuildTag(f *File) {
if !vet("buildtags") {
return
}
- // badf is like File.Badf, but it uses a line number instead of
- // token.Pos.
- badf := func(line int, format string, args ...interface{}) {
- msg := fmt.Sprintf(format, args)
- fmt.Fprintf(os.Stderr, "%s:%d: %s\n", f.name, line, msg)
- setExit(1)
- }
// we must look at the raw lines, as build tags may appear in non-Go
// files such as assembly files.
@@ -92,11 +91,11 @@ func checkBuildTag(f *File) {
fields := bytes.Fields(text)
if !bytes.Equal(fields[0], plusBuild) {
// Comment is something like +buildasdf not +build.
- badf(i+1, "possible malformed +build comment")
+ badfLine(f, i+1, "possible malformed +build comment")
continue
}
if i >= cutoff {
- badf(i+1, "+build comment must appear before package clause and be followed by a blank line")
+ badfLine(f, i+1, "+build comment must appear before package clause and be followed by a blank line")
continue
}
// Check arguments.
@@ -104,13 +103,13 @@ func checkBuildTag(f *File) {
for _, arg := range fields[1:] {
for _, elem := range strings.Split(string(arg), ",") {
if strings.HasPrefix(elem, "!!") {
- badf(i+1, "invalid double negative in build constraint: %s", arg)
+ badfLine(f, i+1, "invalid double negative in build constraint: %s", arg)
break Args
}
elem = strings.TrimPrefix(elem, "!")
for _, c := range elem {
if !unicode.IsLetter(c) && !unicode.IsDigit(c) && c != '_' && c != '.' {
- badf(i+1, "invalid non-alphanumeric build constraint: %s", arg)
+ badfLine(f, i+1, "invalid non-alphanumeric build constraint: %s", arg)
break Args
}
}
@@ -120,7 +119,7 @@ func checkBuildTag(f *File) {
}
// Comment with +build but not at beginning.
if i < cutoff {
- badf(i+1, "possible malformed +build comment")
+ badfLine(f, i+1, "possible malformed +build comment")
continue
}
}
diff --git a/src/cmd/vet/doc.go b/src/cmd/vet/doc.go
index 3df975cacc..d9af0a8875 100644
--- a/src/cmd/vet/doc.go
+++ b/src/cmd/vet/doc.go
@@ -119,22 +119,17 @@ Printf family
Flag: -printf
-Suspicious calls to functions in the Printf family, including any functions
-with these names, disregarding case:
- Print Printf Println
- Fprint Fprintf Fprintln
- Sprint Sprintf Sprintln
- Error Errorf
- Fatal Fatalf
- Log Logf
- Panic Panicf Panicln
-The -printfuncs flag can be used to redefine this list.
-If the function name ends with an 'f', the function is assumed to take
-a format descriptor string in the manner of fmt.Printf. If not, vet
-complains about arguments that look like format descriptor strings.
-
-It also checks for errors such as using a Writer as the first argument of
-Printf.
+Suspicious calls to fmt.Print, fmt.Printf, and related functions.
+The check applies to known functions (for example, those in package fmt)
+as well as any detected wrappers of known functions.
+
+The -printfuncs flag specifies a comma-separated list of names of
+additional known formatting functions. Each name can be of the form
+pkg.Name or pkg.Type.Name, where pkg is a complete import path,
+or else can be a case-insensitive unqualified identifier like "errorf".
+If a listed name ends in f, the function is assumed to be Printf-like,
+taking a format string before the argument list. Otherwise it is
+assumed to be Print-like, taking a list of arguments with no format string.
Range loop variables
diff --git a/src/cmd/vet/main.go b/src/cmd/vet/main.go
index 50af846c59..28da9e2d74 100644
--- a/src/cmd/vet/main.go
+++ b/src/cmd/vet/main.go
@@ -4,10 +4,12 @@
// Vet is a simple checker for static errors in Go source code.
// See doc.go for more information.
+
package main
import (
"bytes"
+ "encoding/gob"
"encoding/json"
"flag"
"fmt"
@@ -24,6 +26,8 @@ import (
"path/filepath"
"strconv"
"strings"
+
+ "cmd/internal/objabi"
)
// Important! If you add flags here, make sure to update cmd/go/internal/vet/vetflag.go.
@@ -154,9 +158,25 @@ var (
// checkers is a two-level map.
// The outer level is keyed by a nil pointer, one of the AST vars above.
// The inner level is keyed by checker name.
- checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ checkers = make(map[ast.Node]map[string]func(*File, ast.Node))
+ pkgCheckers = make(map[string]func(*Package))
+ exporters = make(map[string]func() interface{})
)
+// Vet can provide its own "export information"
+// about package A to future invocations of vet
+// on packages importing A. If B imports A,
+// then running "go vet B" actually invokes vet twice:
+// first, it runs vet on A, in "vetx-only" mode, which
+// skips most checks and only computes export data
+// describing A. Then it runs vet on B, making A's vetx
+// data available for consultation. The vet of B
+// computes vetx data for B in addition to its
+// usual vet checks.
+
+// register registers the named check function,
+// to be called with AST nodes of the given types.
+// The registered functions are not called in vetx-only mode.
func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
report[name] = triStateFlag(name, unset, usage)
for _, typ := range types {
@@ -169,6 +189,25 @@ func register(name, usage string, fn func(*File, ast.Node), types ...ast.Node) {
}
}
+// registerPkgCheck registers a package-level checking function,
+// to be invoked with the whole package being vetted
+// before any of the per-node handlers.
+// The registered function fn is called even in vetx-only mode
+// (see comment above), so fn must take care not to report
+// errors when vcfg.VetxOnly is true.
+func registerPkgCheck(name string, fn func(*Package)) {
+ pkgCheckers[name] = fn
+}
+
+// registerExport registers a function to return vetx export data
+// that should be saved and provided to future invocations of vet
+// when checking packages importing this one.
+// The value returned by fn should be nil or else valid to encode using gob.
+// Typically a registerExport call is paired with a call to gob.Register.
+func registerExport(name string, fn func() interface{}) {
+ exporters[name] = fn
+}
+
// Usage is a replacement usage function for the flags package.
func Usage() {
fmt.Fprintf(os.Stderr, "Usage of vet:\n")
@@ -209,6 +248,7 @@ type File struct {
}
func main() {
+ objabi.AddVersionFlag()
flag.Usage = Usage
flag.Parse()
@@ -295,6 +335,9 @@ type vetConfig struct {
ImportMap map[string]string
PackageFile map[string]string
Standard map[string]bool
+ PackageVetx map[string]string // map from import path to vetx data file
+ VetxOnly bool // only compute vetx output; don't run ordinary checks
+ VetxOutput string // file where vetx output should be written
SucceedOnTypecheckFailure bool
@@ -355,6 +398,21 @@ func doPackageCfg(cfgFile string) {
inittypes()
mustTypecheck = true
doPackage(vcfg.GoFiles, nil)
+ if vcfg.VetxOutput != "" {
+ out := make(map[string]interface{})
+ for name, fn := range exporters {
+ out[name] = fn()
+ }
+ var buf bytes.Buffer
+ if err := gob.NewEncoder(&buf).Encode(out); err != nil {
+ errorf("encoding vet output: %v", err)
+ return
+ }
+ if err := ioutil.WriteFile(vcfg.VetxOutput, buf.Bytes(), 0666); err != nil {
+ errorf("saving vet output: %v", err)
+ return
+ }
+ }
}
// doPackageDir analyzes the single package found in the directory, if there is one,
@@ -431,7 +489,6 @@ func doPackage(names []string, basePkg *Package) *Package {
file: parsedFile,
dead: make(map[ast.Node]bool),
}
- checkBuildTag(file)
files = append(files, file)
}
if len(astFiles) == 0 {
@@ -461,6 +518,19 @@ func doPackage(names []string, basePkg *Package) *Package {
}
// Check.
+ for _, file := range files {
+ file.pkg = pkg
+ file.basePkg = basePkg
+ }
+ for name, fn := range pkgCheckers {
+ if vet(name) {
+ fn(pkg)
+ }
+ }
+ if vcfg.VetxOnly {
+ return pkg
+ }
+
chk := make(map[ast.Node][]func(*File, ast.Node))
for typ, set := range checkers {
for name, fn := range set {
@@ -470,14 +540,12 @@ func doPackage(names []string, basePkg *Package) *Package {
}
}
for _, file := range files {
- file.pkg = pkg
- file.basePkg = basePkg
+ checkBuildTag(file)
file.checkers = chk
if file.file != nil {
file.walkFile(file.name, file.file)
}
}
- asmCheck(pkg)
return pkg
}
@@ -630,3 +698,35 @@ func (f *File) gofmt(x ast.Expr) string {
printer.Fprint(&f.b, f.fset, x)
return f.b.String()
}
+
+// imported[path][key] is previously written export data.
+var imported = make(map[string]map[string]interface{})
+
+// readVetx reads export data written by a previous
+// invocation of vet on an imported package (path).
+// The key is the name passed to registerExport
+// when the data was originally generated.
+// readVetx returns nil if the data is unavailable.
+func readVetx(path, key string) interface{} {
+ if path == "unsafe" || vcfg.ImportPath == "" {
+ return nil
+ }
+ m := imported[path]
+ if m == nil {
+ file := vcfg.PackageVetx[path]
+ if file == "" {
+ return nil
+ }
+ data, err := ioutil.ReadFile(file)
+ if err != nil {
+ return nil
+ }
+ m = make(map[string]interface{})
+ err = gob.NewDecoder(bytes.NewReader(data)).Decode(&m)
+ if err != nil {
+ return nil
+ }
+ imported[path] = m
+ }
+ return m[key]
+}
diff --git a/src/cmd/vet/print.go b/src/cmd/vet/print.go
index 6728d88d45..1edd3dd228 100644
--- a/src/cmd/vet/print.go
+++ b/src/cmd/vet/print.go
@@ -8,6 +8,7 @@ package main
import (
"bytes"
+ "encoding/gob"
"flag"
"fmt"
"go/ast"
@@ -27,6 +28,9 @@ func init() {
"check printf-like invocations",
checkFmtPrintfCall,
funcDecl, callExpr)
+ registerPkgCheck("printf", findPrintfLike)
+ registerExport("printf", exportPrintfLike)
+ gob.Register(map[string]int(nil))
}
func initPrintFlags() {
@@ -44,73 +48,244 @@ func initPrintFlags() {
name = name[:colon]
}
- isPrint[strings.ToLower(name)] = true
+ if !strings.Contains(name, ".") {
+ name = strings.ToLower(name)
+ }
+ isPrint[name] = true
}
}
-// TODO(rsc): Incorporate user-defined printf wrappers again.
-// The general plan is to allow vet of one package P to output
-// additional information to supply to later vets of packages
-// importing P. Then vet of P can record a list of printf wrappers
-// and the later vet using P.Printf will find it in the list and check it.
-// That's not ready for Go 1.10.
-// When that does happen, uncomment the user-defined printf
-// wrapper tests in testdata/print.go.
+var localPrintfLike = make(map[string]int)
+
+type printfWrapper struct {
+ name string
+ fn *ast.FuncDecl
+ format *ast.Field
+ args *ast.Field
+ callers []printfCaller
+ printfLike bool
+}
+
+type printfCaller struct {
+ w *printfWrapper
+ call *ast.CallExpr
+}
+
+// maybePrintfWrapper decides whether decl (a declared function) may be a wrapper
+// around a fmt.Printf or fmt.Print function. If so it returns a printfWrapper
+// function describing the declaration. Later processing will analyze the
+// graph of potential printf wrappers to pick out the ones that are true wrappers.
+// A function may be a Printf or Print wrapper if its last argument is ...interface{}.
+// If the next-to-last argument is a string, then this may be a Printf wrapper.
+// Otherwise it may be a Print wrapper.
+func maybePrintfWrapper(decl ast.Decl) *printfWrapper {
+ // Look for functions with final argument type ...interface{}.
+ fn, ok := decl.(*ast.FuncDecl)
+ if !ok || fn.Body == nil {
+ return nil
+ }
+ name := fn.Name.Name
+ if fn.Recv != nil {
+ // For (*T).Name or T.name, use "T.name".
+ rcvr := fn.Recv.List[0].Type
+ if ptr, ok := rcvr.(*ast.StarExpr); ok {
+ rcvr = ptr.X
+ }
+ id, ok := rcvr.(*ast.Ident)
+ if !ok {
+ return nil
+ }
+ name = id.Name + "." + name
+ }
+ params := fn.Type.Params.List
+ if len(params) == 0 {
+ return nil
+ }
+ args := params[len(params)-1]
+ if len(args.Names) != 1 {
+ return nil
+ }
+ ddd, ok := args.Type.(*ast.Ellipsis)
+ if !ok {
+ return nil
+ }
+ iface, ok := ddd.Elt.(*ast.InterfaceType)
+ if !ok || len(iface.Methods.List) > 0 {
+ return nil
+ }
+ var format *ast.Field
+ if len(params) >= 2 {
+ p := params[len(params)-2]
+ if len(p.Names) == 1 {
+ if id, ok := p.Type.(*ast.Ident); ok && id.Name == "string" {
+ format = p
+ }
+ }
+ }
+
+ return &printfWrapper{
+ name: name,
+ fn: fn,
+ format: format,
+ args: args,
+ }
+}
+
+// findPrintfLike scans the entire package to find printf-like functions.
+func findPrintfLike(pkg *Package) {
+ if vcfg.ImportPath == "" { // no type or vetx information; don't bother
+ return
+ }
+
+ // Gather potential wrappesr and call graph between them.
+ byName := make(map[string]*printfWrapper)
+ var wrappers []*printfWrapper
+ for _, file := range pkg.files {
+ if file.file == nil {
+ continue
+ }
+ for _, decl := range file.file.Decls {
+ w := maybePrintfWrapper(decl)
+ if w == nil {
+ continue
+ }
+ byName[w.name] = w
+ wrappers = append(wrappers, w)
+ }
+ }
+
+ // Walk the graph to figure out which are really printf wrappers.
+ for _, w := range wrappers {
+ // Scan function for calls that could be to other printf-like functions.
+ ast.Inspect(w.fn.Body, func(n ast.Node) bool {
+ call, ok := n.(*ast.CallExpr)
+ if !ok || len(call.Args) == 0 || !match(call.Args[len(call.Args)-1], w.args) {
+ return true
+ }
+
+ pkgpath, name, kind := printfNameAndKind(pkg, call.Fun)
+ if kind != 0 {
+ checkPrintfFwd(pkg, w, call, kind)
+ return true
+ }
+
+ // If the call is to another function in this package,
+ // maybe we will find out it is printf-like later.
+ // Remember this call for later checking.
+ if pkgpath == "" && byName[name] != nil {
+ callee := byName[name]
+ callee.callers = append(callee.callers, printfCaller{w, call})
+ }
+
+ return true
+ })
+ }
+}
+
+func match(arg ast.Expr, param *ast.Field) bool {
+ id, ok := arg.(*ast.Ident)
+ return ok && id.Obj != nil && id.Obj.Decl == param
+}
+
+const (
+ kindPrintf = 1
+ kindPrint = 2
+)
+
+// printfLike reports whether a call to fn should be considered a call to a printf-like function.
+// It returns 0 (indicating not a printf-like function), kindPrintf, or kindPrint.
+func printfLike(pkg *Package, fn ast.Expr, byName map[string]*printfWrapper) int {
+ if id, ok := fn.(*ast.Ident); ok && id.Obj != nil {
+ if w := byName[id.Name]; w != nil && id.Obj.Decl == w.fn {
+ // Found call to function in same package.
+ return localPrintfLike[id.Name]
+ }
+ }
+ if sel, ok := fn.(*ast.SelectorExpr); ok {
+ if id, ok := sel.X.(*ast.Ident); ok && id.Name == "fmt" && strings.Contains(sel.Sel.Name, "rint") {
+ if strings.HasSuffix(sel.Sel.Name, "f") {
+ return kindPrintf
+ }
+ return kindPrint
+ }
+ }
+ return 0
+}
+
+// checkPrintfFwd checks that a printf-forwarding wrapper is forwarding correctly.
+// It diagnoses writing fmt.Printf(format, args) instead of fmt.Printf(format, args...).
+func checkPrintfFwd(pkg *Package, w *printfWrapper, call *ast.CallExpr, kind int) {
+ matched := kind == kindPrint ||
+ kind == kindPrintf && len(call.Args) >= 2 && match(call.Args[len(call.Args)-2], w.format)
+ if !matched {
+ return
+ }
+
+ if !call.Ellipsis.IsValid() {
+ if !vcfg.VetxOnly {
+ desc := "printf"
+ if kind == kindPrint {
+ desc = "print"
+ }
+ pkg.files[0].Badf(call.Pos(), "missing ... in args forwarded to %s-like function", desc)
+ }
+ return
+ }
+ name := w.name
+ if localPrintfLike[name] == 0 {
+ localPrintfLike[name] = kind
+ for _, caller := range w.callers {
+ checkPrintfFwd(pkg, caller.w, caller.call, kind)
+ }
+ }
+}
+
+func exportPrintfLike() interface{} {
+ return localPrintfLike
+}
// isPrint records the print functions.
// If a key ends in 'f' then it is assumed to be a formatted print.
var isPrint = map[string]bool{
- "fmt.Errorf": true,
- "fmt.Fprint": true,
- "fmt.Fprintf": true,
- "fmt.Fprintln": true,
- "fmt.Print": true,
- "fmt.Printf": true,
- "fmt.Println": true,
- "fmt.Sprint": true,
- "fmt.Sprintf": true,
- "fmt.Sprintln": true,
- "log.Fatal": true,
- "log.Fatalf": true,
- "log.Fatalln": true,
- "log.Logger.Fatal": true,
- "log.Logger.Fatalf": true,
- "log.Logger.Fatalln": true,
- "log.Logger.Panic": true,
- "log.Logger.Panicf": true,
- "log.Logger.Panicln": true,
- "log.Logger.Printf": true,
- "log.Logger.Println": true,
- "log.Panic": true,
- "log.Panicf": true,
- "log.Panicln": true,
- "log.Print": true,
- "log.Printf": true,
- "log.Println": true,
- "testing.B.Error": true,
- "testing.B.Errorf": true,
- "testing.B.Fatal": true,
- "testing.B.Fatalf": true,
- "testing.B.Log": true,
- "testing.B.Logf": true,
- "testing.B.Skip": true,
- "testing.B.Skipf": true,
- "testing.T.Error": true,
- "testing.T.Errorf": true,
- "testing.T.Fatal": true,
- "testing.T.Fatalf": true,
- "testing.T.Log": true,
- "testing.T.Logf": true,
- "testing.T.Skip": true,
- "testing.T.Skipf": true,
- "testing.TB.Error": true,
- "testing.TB.Errorf": true,
- "testing.TB.Fatal": true,
- "testing.TB.Fatalf": true,
- "testing.TB.Log": true,
- "testing.TB.Logf": true,
- "testing.TB.Skip": true,
- "testing.TB.Skipf": true,
+ "fmt.Errorf": true,
+ "fmt.Fprint": true,
+ "fmt.Fprintf": true,
+ "fmt.Fprintln": true,
+ "fmt.Print": true,
+ "fmt.Printf": true,
+ "fmt.Println": true,
+ "fmt.Sprint": true,
+ "fmt.Sprintf": true,
+ "fmt.Sprintln": true,
+
+ // testing.B, testing.T not auto-detected
+ // because the methods are picked up by embedding.
+ "testing.B.Error": true,
+ "testing.B.Errorf": true,
+ "testing.B.Fatal": true,
+ "testing.B.Fatalf": true,
+ "testing.B.Log": true,
+ "testing.B.Logf": true,
+ "testing.B.Skip": true,
+ "testing.B.Skipf": true,
+ "testing.T.Error": true,
+ "testing.T.Errorf": true,
+ "testing.T.Fatal": true,
+ "testing.T.Fatalf": true,
+ "testing.T.Log": true,
+ "testing.T.Logf": true,
+ "testing.T.Skip": true,
+ "testing.T.Skipf": true,
+
+ // testing.TB is an interface, so can't detect wrapping.
+ "testing.TB.Error": true,
+ "testing.TB.Errorf": true,
+ "testing.TB.Fatal": true,
+ "testing.TB.Fatalf": true,
+ "testing.TB.Log": true,
+ "testing.TB.Logf": true,
+ "testing.TB.Skip": true,
+ "testing.TB.Skipf": true,
}
// formatString returns the format string argument and its index within
@@ -206,66 +381,84 @@ func checkFmtPrintfCall(f *File, node ast.Node) {
}
// Construct name like pkg.Printf or pkg.Type.Printf for lookup.
- var name string
- switch x := call.Fun.(type) {
+ _, name, kind := printfNameAndKind(f.pkg, call.Fun)
+ if kind == kindPrintf {
+ f.checkPrintf(call, name)
+ }
+ if kind == kindPrint {
+ f.checkPrint(call, name)
+ }
+}
+
+func printfName(pkg *Package, called ast.Expr) (pkgpath, name string) {
+ switch x := called.(type) {
case *ast.Ident:
- if fn, ok := f.pkg.uses[x].(*types.Func); ok {
- var pkg string
- if fn.Pkg() == nil || fn.Pkg() == f.pkg.typesPkg {
- pkg = vcfg.ImportPath
+ if fn, ok := pkg.uses[x].(*types.Func); ok {
+ if fn.Pkg() == nil || fn.Pkg() == pkg.typesPkg {
+ pkgpath = ""
} else {
- pkg = fn.Pkg().Path()
+ pkgpath = fn.Pkg().Path()
}
- name = pkg + "." + x.Name
- break
+ return pkgpath, x.Name
}
case *ast.SelectorExpr:
// Check for "fmt.Printf".
if id, ok := x.X.(*ast.Ident); ok {
- if pkgName, ok := f.pkg.uses[id].(*types.PkgName); ok {
- name = pkgName.Imported().Path() + "." + x.Sel.Name
- break
+ if pkgName, ok := pkg.uses[id].(*types.PkgName); ok {
+ return pkgName.Imported().Path(), x.Sel.Name
}
}
// Check for t.Logf where t is a *testing.T.
- if sel := f.pkg.selectors[x]; sel != nil {
+ if sel := pkg.selectors[x]; sel != nil {
recv := sel.Recv()
if p, ok := recv.(*types.Pointer); ok {
recv = p.Elem()
}
if named, ok := recv.(*types.Named); ok {
obj := named.Obj()
- var pkg string
- if obj.Pkg() == nil || obj.Pkg() == f.pkg.typesPkg {
- pkg = vcfg.ImportPath
+ if obj.Pkg() == nil || obj.Pkg() == pkg.typesPkg {
+ pkgpath = ""
} else {
- pkg = obj.Pkg().Path()
+ pkgpath = obj.Pkg().Path()
}
- name = pkg + "." + obj.Name() + "." + x.Sel.Name
- break
+ return pkgpath, obj.Name() + "." + x.Sel.Name
}
}
}
+ return "", ""
+}
+
+func printfNameAndKind(pkg *Package, called ast.Expr) (pkgpath, name string, kind int) {
+ pkgpath, name = printfName(pkg, called)
if name == "" {
- return
+ return pkgpath, name, 0
}
- shortName := name[strings.LastIndex(name, ".")+1:]
-
- _, ok = isPrint[name]
- if !ok {
- // Next look up just "printf", for use with -printfuncs.
- _, ok = isPrint[strings.ToLower(shortName)]
+ if pkgpath == "" {
+ kind = localPrintfLike[name]
+ } else {
+ printfLike, _ := readVetx(pkgpath, "printf").(map[string]int)
+ kind = printfLike[name]
}
- if ok {
- if strings.HasSuffix(name, "f") {
- f.checkPrintf(call, shortName)
- } else {
- f.checkPrint(call, shortName)
+
+ if kind == 0 {
+ _, ok := isPrint[pkgpath+"."+name]
+ if !ok {
+ // Next look up just "printf", for use with -printfuncs.
+ short := name[strings.LastIndex(name, ".")+1:]
+ _, ok = isPrint[strings.ToLower(short)]
+ }
+ if ok {
+ if strings.HasSuffix(name, "f") {
+ kind = kindPrintf
+ } else {
+ kind = kindPrint
+ }
}
}
+ return pkgpath, name, kind
}
// isStringer returns true if the provided declaration is a "String() string"
diff --git a/src/cmd/vet/testdata/buildtag/buildtag.go b/src/cmd/vet/testdata/buildtag/buildtag.go
index 6ee08da638..c2fd6aaaf2 100644
--- a/src/cmd/vet/testdata/buildtag/buildtag.go
+++ b/src/cmd/vet/testdata/buildtag/buildtag.go
@@ -9,7 +9,7 @@
package testdata
-// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line"
+// +build toolate // ERROR "build comment must appear before package clause and be followed by a blank line$"
var _ = 3
diff --git a/src/cmd/vet/testdata/print.go b/src/cmd/vet/testdata/print.go
index 34f4e2865a..16f46a4897 100644
--- a/src/cmd/vet/testdata/print.go
+++ b/src/cmd/vet/testdata/print.go
@@ -14,6 +14,7 @@ package testdata
import (
"fmt"
. "fmt"
+ logpkg "log" // renamed to make it harder to see
"math"
"os"
"testing"
@@ -175,6 +176,18 @@ func PrintfTests() {
f.Warnf(0, "%s", "hello", 3) // ERROR "Warnf call needs 1 arg but has 2 args"
f.Warnf(0, "%r", "hello") // ERROR "Warnf format %r has unknown verb r"
f.Warnf(0, "%#s", "hello") // ERROR "Warnf format %#s has unrecognized flag #"
+ f.Warn2(0, "%s", "hello", 3) // ERROR "Warn2 call has possible formatting directive %s"
+ f.Warnf2(0, "%s", "hello", 3) // ERROR "Warnf2 call needs 1 arg but has 2 args"
+ f.Warnf2(0, "%r", "hello") // ERROR "Warnf2 format %r has unknown verb r"
+ f.Warnf2(0, "%#s", "hello") // ERROR "Warnf2 format %#s has unrecognized flag #"
+ f.Wrap(0, "%s", "hello", 3) // ERROR "Wrap call has possible formatting directive %s"
+ f.Wrapf(0, "%s", "hello", 3) // ERROR "Wrapf call needs 1 arg but has 2 args"
+ f.Wrapf(0, "%r", "hello") // ERROR "Wrapf format %r has unknown verb r"
+ f.Wrapf(0, "%#s", "hello") // ERROR "Wrapf format %#s has unrecognized flag #"
+ f.Wrap2(0, "%s", "hello", 3) // ERROR "Wrap2 call has possible formatting directive %s"
+ f.Wrapf2(0, "%s", "hello", 3) // ERROR "Wrapf2 call needs 1 arg but has 2 args"
+ f.Wrapf2(0, "%r", "hello") // ERROR "Wrapf2 format %r has unknown verb r"
+ f.Wrapf2(0, "%#s", "hello") // ERROR "Wrapf2 format %#s has unrecognized flag #"
fmt.Printf("%#s", FormatterVal(true)) // correct (the type is responsible for formatting)
Printf("d%", 2) // ERROR "Printf format % is missing verb at end of string"
Printf("%d", percentDV)
@@ -283,6 +296,28 @@ func PrintfTests() {
Printf(someString(), "hello") // OK
+ // Printf wrappers in package log should be detected automatically
+ logpkg.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d"
+ logpkg.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d"
+ logpkg.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d"
+ logpkg.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d"
+ logpkg.Print("%d", 1) // ERROR "Print call has possible formatting directive %d"
+ logpkg.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string"
+ logpkg.Println("%d", 1) // ERROR "Println call has possible formatting directive %d"
+
+ // Methods too.
+ var l *logpkg.Logger
+ l.Fatal("%d", 1) // ERROR "Fatal call has possible formatting directive %d"
+ l.Fatalf("%d", "x") // ERROR "Fatalf format %d has arg \x22x\x22 of wrong type string"
+ l.Fatalln("%d", 1) // ERROR "Fatalln call has possible formatting directive %d"
+ l.Panic("%d", 1) // ERROR "Panic call has possible formatting directive %d"
+ l.Panicf("%d", "x") // ERROR "Panicf format %d has arg \x22x\x22 of wrong type string"
+ l.Panicln("%d", 1) // ERROR "Panicln call has possible formatting directive %d"
+ l.Print("%d", 1) // ERROR "Print call has possible formatting directive %d"
+ l.Printf("%d", "x") // ERROR "Printf format %d has arg \x22x\x22 of wrong type string"
+ l.Println("%d", 1) // ERROR "Println call has possible formatting directive %d"
}
func someString() string { return "X" }
@@ -368,14 +403,46 @@ func (*ptrStringer) String() string {
return "string"
}
-func (*ptrStringer) Warn(int, ...interface{}) string {
+func (p *ptrStringer) Warn2(x int, args ...interface{}) string {
+ return p.Warn(x, args...)
+}
+
+func (p *ptrStringer) Warnf2(x int, format string, args ...interface{}) string {
+ return p.Warnf(x, format, args...)
+}
+
+func (*ptrStringer) Warn(x int, args ...interface{}) string {
return "warn"
}
-func (*ptrStringer) Warnf(int, string, ...interface{}) string {
+func (*ptrStringer) Warnf(x int, format string, args ...interface{}) string {
return "warnf"
}
+func (p *ptrStringer) Wrap2(x int, args ...interface{}) string {
+ return p.Wrap(x, args...)
+}
+
+func (p *ptrStringer) Wrapf2(x int, format string, args ...interface{}) string {
+ return p.Wrapf(x, format, args...)
+}
+
+func (*ptrStringer) Wrap(x int, args ...interface{}) string {
+ return fmt.Sprint(args...)
+}
+
+func (*ptrStringer) Wrapf(x int, format string, args ...interface{}) string {
+ return fmt.Sprintf(format, args...)
+}
+
+func (*ptrStringer) BadWrap(x int, args ...interface{}) string {
+ return fmt.Sprint(args) // ERROR "missing ... in args forwarded to print-like function"
+}
+
+func (*ptrStringer) BadWrapf(x int, format string, args ...interface{}) string {
+ return fmt.Sprintf(format, args) // ERROR "missing ... in args forwarded to printf-like function"
+}
+
type embeddedStringer struct {
foo string
ptrStringer
diff --git a/src/context/example_test.go b/src/context/example_test.go
index b2c2aa921d..2b28b57704 100644
--- a/src/context/example_test.go
+++ b/src/context/example_test.go
@@ -93,6 +93,8 @@ func ExampleWithTimeout() {
// context deadline exceeded
}
+// This example demonstrates how a value can be passed to the context
+// and also how to retrieve it if it exists.
func ExampleWithValue() {
type favContextKey string
diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go
index c1cacdb752..13ae2fcb82 100644
--- a/src/crypto/aes/aes_gcm.go
+++ b/src/crypto/aes/aes_gcm.go
@@ -8,6 +8,7 @@ package aes
import (
"crypto/cipher"
+ subtleoverlap "crypto/internal/subtle"
"crypto/subtle"
"errors"
)
@@ -99,10 +100,10 @@ func sliceForAppend(in []byte, n int) (head, tail []byte) {
// details.
func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
- panic("cipher: message too large for GCM")
+ panic("crypto/cipher: message too large for GCM")
}
var counter, tagMask [gcmBlockSize]byte
@@ -123,6 +124,9 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
gcmAesData(&g.productTable, data, &tagOut)
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if len(plaintext) > 0 {
gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
}
@@ -136,12 +140,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details.
func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
// Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize {
- panic("cipher: incorrect GCM tag size")
+ panic("crypto/cipher: incorrect GCM tag size")
}
if len(ciphertext) < g.tagSize {
@@ -173,6 +177,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
gcmAesData(&g.productTable, data, &expectedTag)
ret, out := sliceForAppend(dst, len(ciphertext))
+ if subtleoverlap.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if len(ciphertext) > 0 {
gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
}
diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go
index 739e1febc3..28a6b1d546 100644
--- a/src/crypto/aes/cbc_s390x.go
+++ b/src/crypto/aes/cbc_s390x.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/subtle"
)
// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
@@ -48,6 +49,9 @@ func (x *cbc) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if len(src) > 0 {
cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
}
diff --git a/src/crypto/aes/cipher.go b/src/crypto/aes/cipher.go
index fbd01a8f40..db0ee38b78 100644
--- a/src/crypto/aes/cipher.go
+++ b/src/crypto/aes/cipher.go
@@ -7,6 +7,7 @@ package aes
import (
"crypto/cipher"
"crypto/internal/boring"
+ "crypto/internal/subtle"
"strconv"
)
@@ -61,6 +62,9 @@ func (c *aesCipher) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
encryptBlockGo(c.enc, dst, src)
}
@@ -71,5 +75,8 @@ func (c *aesCipher) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
decryptBlockGo(c.dec, dst, src)
}
diff --git a/src/crypto/aes/cipher_amd64.go b/src/crypto/aes/cipher_amd64.go
index 7efab31065..fd88343cae 100644
--- a/src/crypto/aes/cipher_amd64.go
+++ b/src/crypto/aes/cipher_amd64.go
@@ -7,6 +7,7 @@ package aes
import (
"crypto/cipher"
"crypto/internal/boring"
+ "crypto/internal/subtle"
"internal/cpu"
)
@@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
}
@@ -65,6 +69,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
}
diff --git a/src/crypto/aes/cipher_arm64.go b/src/crypto/aes/cipher_arm64.go
index c8027eec8b..a03547841f 100644
--- a/src/crypto/aes/cipher_arm64.go
+++ b/src/crypto/aes/cipher_arm64.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/subtle"
"internal/cpu"
"math/bits"
)
@@ -40,6 +41,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
}
@@ -50,6 +54,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
}
diff --git a/src/crypto/aes/cipher_ppc64le.go b/src/crypto/aes/cipher_ppc64le.go
index 110f61f57c..b788ea7d47 100644
--- a/src/crypto/aes/cipher_ppc64le.go
+++ b/src/crypto/aes/cipher_ppc64le.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/subtle"
)
// defined in asm_ppc64le.s
@@ -54,6 +55,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
encryptBlockAsm(&dst[0], &src[0], &c.enc[0])
}
@@ -64,6 +68,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
decryptBlockAsm(&dst[0], &src[0], &c.dec[0])
}
diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go
index 93e3b929b9..65b6b2fc1b 100644
--- a/src/crypto/aes/cipher_s390x.go
+++ b/src/crypto/aes/cipher_s390x.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/subtle"
"internal/cpu"
)
@@ -31,12 +32,11 @@ type aesCipherAsm struct {
func cryptBlocks(c code, key, dst, src *byte, length int)
func newCipher(key []byte) (cipher.Block, error) {
- // Strictly speaking, this check should be for HasKM.
- // The check for HasKMC and HasKMCTR provides compatibility
- // with the existing optimized s390x CBC and CTR implementations
- // in this package, which already assert that they meet the
- // cbcEncAble, cbcDecAble, and ctrAble interfaces
- if !(cpu.S390X.HasKM && cpu.S390X.HasKMC && cpu.S390X.HasKMCTR) {
+ // The aesCipherAsm type implements the cbcEncAble, cbcDecAble,
+ // ctrAble and gcmAble interfaces. We therefore need to check
+ // for all the features required to implement these modes.
+ // Keep in sync with crypto/tls/common.go.
+ if !(cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)) {
return newCipherGeneric(key)
}
@@ -68,6 +68,9 @@ func (c *aesCipherAsm) Encrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
}
@@ -78,6 +81,9 @@ func (c *aesCipherAsm) Decrypt(dst, src []byte) {
if len(dst) < BlockSize {
panic("crypto/aes: output not full block")
}
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
// The decrypt function code is equal to the function code + 128.
cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
}
diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go
index 8078aa6802..8fa85a3ae8 100644
--- a/src/crypto/aes/ctr_s390x.go
+++ b/src/crypto/aes/ctr_s390x.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ "crypto/internal/subtle"
"unsafe"
)
@@ -64,9 +65,11 @@ func (c *aesctr) refill() {
}
func (c *aesctr) XORKeyStream(dst, src []byte) {
- if len(src) > 0 {
- // Assert len(dst) >= len(src)
- _ = dst[len(src)-1]
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
}
for len(src) > 0 {
if len(c.buffer) == 0 {
diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go
index acac6ec7b6..d154ddbaa0 100644
--- a/src/crypto/aes/gcm_s390x.go
+++ b/src/crypto/aes/gcm_s390x.go
@@ -6,6 +6,7 @@ package aes
import (
"crypto/cipher"
+ subtleoverlap "crypto/internal/subtle"
"crypto/subtle"
"errors"
"internal/cpu"
@@ -85,7 +86,7 @@ func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
nonceSize: nonceSize,
tagSize: tagSize,
}
- if cpu.S390X.HasKMA {
+ if cpu.S390X.HasAESGCM {
g := gcmKMA{g}
return &g, nil
}
@@ -220,13 +221,16 @@ func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSi
// details.
func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
- panic("cipher: message too large for GCM")
+ panic("crypto/cipher: message too large for GCM")
}
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
counter := g.deriveCounter(nonce)
@@ -246,12 +250,12 @@ func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details.
func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
// Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize {
- panic("cipher: incorrect GCM tag size")
+ panic("crypto/cipher: incorrect GCM tag size")
}
if len(ciphertext) < g.tagSize {
return nil, errOpen
@@ -273,6 +277,9 @@ func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
g.auth(expectedTag[:], ciphertext, data, &tagMask)
ret, out := sliceForAppend(dst, len(ciphertext))
+ if subtleoverlap.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and
@@ -314,13 +321,16 @@ func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
// details.
func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
- panic("cipher: message too large for GCM")
+ panic("crypto/cipher: message too large for GCM")
}
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if subtleoverlap.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
counter := g.deriveCounter(nonce)
fc := g.block.function | kmaLAAD | kmaLPC
@@ -336,7 +346,7 @@ func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
// for details.
func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
if len(ciphertext) < g.tagSize {
return nil, errOpen
@@ -348,9 +358,12 @@ func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
tag := ciphertext[len(ciphertext)-g.tagSize:]
ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
ret, out := sliceForAppend(dst, len(ciphertext))
+ if subtleoverlap.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if g.tagSize < gcmMinimumTagSize {
- panic("cipher: incorrect GCM tag size")
+ panic("crypto/cipher: incorrect GCM tag size")
}
counter := g.deriveCounter(nonce)
diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go
index 0367d5971a..0d07192e29 100644
--- a/src/crypto/cipher/cbc.go
+++ b/src/crypto/cipher/cbc.go
@@ -11,6 +11,8 @@
package cipher
+import "crypto/internal/subtle"
+
type cbc struct {
b Block
blockSize int
@@ -59,6 +61,9 @@ func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
iv := x.iv
@@ -116,6 +121,9 @@ func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
if len(dst) < len(src) {
panic("crypto/cipher: output smaller than input")
}
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if len(src) == 0 {
return
}
diff --git a/src/crypto/cipher/cfb.go b/src/crypto/cipher/cfb.go
index 9b4eebf5b4..80c9bc24ea 100644
--- a/src/crypto/cipher/cfb.go
+++ b/src/crypto/cipher/cfb.go
@@ -6,6 +6,8 @@
package cipher
+import "crypto/internal/subtle"
+
type cfb struct {
b Block
next []byte
@@ -16,6 +18,12 @@ type cfb struct {
}
func (x *cfb) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
for len(src) > 0 {
if x.outUsed == len(x.out) {
x.b.Encrypt(x.out, x.next)
diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go
index 75f46cfe51..cba028d2a4 100644
--- a/src/crypto/cipher/ctr.go
+++ b/src/crypto/cipher/ctr.go
@@ -12,6 +12,8 @@
package cipher
+import "crypto/internal/subtle"
+
type ctr struct {
b Block
ctr []byte
@@ -71,6 +73,12 @@ func (x *ctr) refill() {
}
func (x *ctr) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill()
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
index 28f8b2093e..6321e9e82d 100644
--- a/src/crypto/cipher/gcm.go
+++ b/src/crypto/cipher/gcm.go
@@ -5,6 +5,7 @@
package cipher
import (
+ subtleoverlap "crypto/internal/subtle"
"crypto/subtle"
"errors"
)
@@ -26,8 +27,8 @@ type AEAD interface {
// slice. The nonce must be NonceSize() bytes long and unique for all
// time, for a given key.
//
- // The plaintext and dst must overlap exactly or not at all. To reuse
- // plaintext's storage for the encrypted output, use plaintext[:0] as dst.
+ // To reuse plaintext's storage for the encrypted output, use plaintext[:0]
+ // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
Seal(dst, nonce, plaintext, additionalData []byte) []byte
// Open decrypts and authenticates ciphertext, authenticates the
@@ -36,8 +37,8 @@ type AEAD interface {
// bytes long and both it and the additional data must match the
// value passed to Seal.
//
- // The ciphertext and dst must overlap exactly or not at all. To reuse
- // ciphertext's storage for the decrypted output, use ciphertext[:0] as dst.
+ // To reuse ciphertext's storage for the decrypted output, use ciphertext[:0]
+ // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
//
// Even if the function fails, the contents of dst, up to its capacity,
// may be overwritten.
@@ -159,13 +160,16 @@ func (g *gcm) Overhead() int {
func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) {
- panic("cipher: message too large for GCM")
+ panic("crypto/cipher: message too large for GCM")
}
ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if subtleoverlap.InexactOverlap(out, plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
var counter, tagMask [gcmBlockSize]byte
g.deriveCounter(&counter, nonce)
@@ -186,12 +190,12 @@ var errOpen = errors.New("cipher: message authentication failed")
func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
if len(nonce) != g.nonceSize {
- panic("cipher: incorrect nonce length given to GCM")
+ panic("crypto/cipher: incorrect nonce length given to GCM")
}
// Sanity check to prevent the authentication from always succeeding if an implementation
// leaves tagSize uninitialized, for example.
if g.tagSize < gcmMinimumTagSize {
- panic("cipher: incorrect GCM tag size")
+ panic("crypto/cipher: incorrect GCM tag size")
}
if len(ciphertext) < g.tagSize {
@@ -214,6 +218,9 @@ func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
g.auth(expectedTag[:], ciphertext, data, &tagMask)
ret, out := sliceForAppend(dst, len(ciphertext))
+ if subtleoverlap.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
// The AESNI code decrypts and authenticates concurrently, and
diff --git a/src/crypto/cipher/ofb.go b/src/crypto/cipher/ofb.go
index 7b35f8995c..fc47724865 100644
--- a/src/crypto/cipher/ofb.go
+++ b/src/crypto/cipher/ofb.go
@@ -6,6 +6,8 @@
package cipher
+import "crypto/internal/subtle"
+
type ofb struct {
b Block
cipher []byte
@@ -54,6 +56,12 @@ func (x *ofb) refill() {
}
func (x *ofb) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
for len(src) > 0 {
if x.outUsed >= len(x.out)-x.b.BlockSize() {
x.refill()
diff --git a/src/crypto/des/cipher.go b/src/crypto/des/cipher.go
index 46af5b0f02..9e6779c216 100644
--- a/src/crypto/des/cipher.go
+++ b/src/crypto/des/cipher.go
@@ -6,6 +6,7 @@ package des
import (
"crypto/cipher"
+ "crypto/internal/subtle"
"encoding/binary"
"strconv"
)
@@ -37,9 +38,31 @@ func NewCipher(key []byte) (cipher.Block, error) {
func (c *desCipher) BlockSize() int { return BlockSize }
-func (c *desCipher) Encrypt(dst, src []byte) { encryptBlock(c.subkeys[:], dst, src) }
+func (c *desCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+ encryptBlock(c.subkeys[:], dst, src)
+}
-func (c *desCipher) Decrypt(dst, src []byte) { decryptBlock(c.subkeys[:], dst, src) }
+func (c *desCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+ decryptBlock(c.subkeys[:], dst, src)
+}
// A tripleDESCipher is an instance of TripleDES encryption.
type tripleDESCipher struct {
@@ -62,6 +85,16 @@ func NewTripleDESCipher(key []byte) (cipher.Block, error) {
func (c *tripleDESCipher) BlockSize() int { return BlockSize }
func (c *tripleDESCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+
b := binary.BigEndian.Uint64(src)
b = permuteInitialBlock(b)
left, right := uint32(b>>32), uint32(b)
@@ -87,6 +120,16 @@ func (c *tripleDESCipher) Encrypt(dst, src []byte) {
}
func (c *tripleDESCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if subtle.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+
b := binary.BigEndian.Uint64(src)
b = permuteInitialBlock(b)
left, right := uint32(b>>32), uint32(b)
diff --git a/src/crypto/internal/subtle/aliasing.go b/src/crypto/internal/subtle/aliasing.go
new file mode 100644
index 0000000000..812ce3c655
--- /dev/null
+++ b/src/crypto/internal/subtle/aliasing.go
@@ -0,0 +1,34 @@
+// Copyright 2018 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 !appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+//
+// This is a mirror of golang.org/x/crypto/internal/subtle.
+package subtle // import "crypto/internal/subtle"
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/src/crypto/internal/subtle/aliasing_appengine.go b/src/crypto/internal/subtle/aliasing_appengine.go
new file mode 100644
index 0000000000..844f901d18
--- /dev/null
+++ b/src/crypto/internal/subtle/aliasing_appengine.go
@@ -0,0 +1,37 @@
+// Copyright 2018 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 appengine
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+//
+// This is a mirror of golang.org/x/crypto/internal/subtle.
+package subtle // import "crypto/internal/subtle"
+
+// This is the Google App Engine standard variant based on reflect
+// because the unsafe package and cgo are disallowed.
+
+import "reflect"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ reflect.ValueOf(&x[0]).Pointer() <= reflect.ValueOf(&y[len(y)-1]).Pointer() &&
+ reflect.ValueOf(&y[0]).Pointer() <= reflect.ValueOf(&x[len(x)-1]).Pointer()
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/src/crypto/internal/subtle/aliasing_test.go b/src/crypto/internal/subtle/aliasing_test.go
new file mode 100644
index 0000000000..f1e7238481
--- /dev/null
+++ b/src/crypto/internal/subtle/aliasing_test.go
@@ -0,0 +1,50 @@
+// Copyright 2018 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 subtle_test
+
+import (
+ "testing"
+
+ "crypto/internal/subtle"
+)
+
+var a, b [100]byte
+
+var aliasingTests = []struct {
+ x, y []byte
+ anyOverlap, inexactOverlap bool
+}{
+ {a[:], b[:], false, false},
+ {a[:], b[:0], false, false},
+ {a[:], b[:50], false, false},
+ {a[40:50], a[50:60], false, false},
+ {a[40:50], a[60:70], false, false},
+ {a[:51], a[50:], true, true},
+ {a[:], a[:], true, false},
+ {a[:50], a[:60], true, false},
+ {a[:], nil, false, false},
+ {nil, nil, false, false},
+ {a[:], a[:0], false, false},
+ {a[:10], a[:10:20], true, false},
+ {a[:10], a[5:10:20], true, true},
+}
+
+func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) {
+ any := subtle.AnyOverlap(x, y)
+ if any != anyOverlap {
+ t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any)
+ }
+ inexact := subtle.InexactOverlap(x, y)
+ if inexact != inexactOverlap {
+ t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any)
+ }
+}
+
+func TestAliasing(t *testing.T) {
+ for i, tt := range aliasingTests {
+ testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap)
+ testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap)
+ }
+}
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
index e80ad368a2..b8df8a3711 100644
--- a/src/crypto/rand/rand.go
+++ b/src/crypto/rand/rand.go
@@ -3,13 +3,13 @@
// license that can be found in the LICENSE file.
// Package rand implements a cryptographically secure
-// pseudorandom number generator.
+// random number generator.
package rand
import "io"
// Reader is a global, shared instance of a cryptographically
-// strong pseudo-random generator.
+// secure random number generator.
//
// On Linux, Reader uses getrandom(2) if available, /dev/urandom otherwise.
// On OpenBSD, Reader uses getentropy(2).
diff --git a/src/crypto/rand/rand_js.go b/src/crypto/rand/rand_js.go
index bc54ccd37d..bb213963fd 100644
--- a/src/crypto/rand/rand_js.go
+++ b/src/crypto/rand/rand_js.go
@@ -12,7 +12,7 @@ func init() {
Reader = &reader{}
}
-var jsCrypto = js.Global.Get("crypto")
+var jsCrypto = js.Global().Get("crypto")
// reader implements a pseudorandom generator
// using JavaScript crypto.getRandomValues method.
@@ -20,6 +20,8 @@ var jsCrypto = js.Global.Get("crypto")
type reader struct{}
func (r *reader) Read(b []byte) (int, error) {
- jsCrypto.Call("getRandomValues", b)
+ a := js.TypedArrayOf(b)
+ jsCrypto.Call("getRandomValues", a)
+ a.Release()
return len(b), nil
}
diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
index cf08ba7f8c..c445bb078f 100644
--- a/src/crypto/rc4/rc4.go
+++ b/src/crypto/rc4/rc4.go
@@ -9,7 +9,10 @@
// applications.
package rc4
-import "strconv"
+import (
+ "crypto/internal/subtle"
+ "strconv"
+)
// A Cipher is an instance of RC4 using a particular key.
type Cipher struct {
@@ -60,6 +63,9 @@ func (c *Cipher) xorKeyStreamGeneric(dst, src []byte) {
if len(src) == 0 {
return
}
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/rc4: invalid buffer overlap")
+ }
i, j := c.i, c.j
_ = dst[len(src)-1]
dst = dst[:len(src)] // eliminate bounds check from loop
diff --git a/src/crypto/rc4/rc4_asm.go b/src/crypto/rc4/rc4_asm.go
index 7e5f8b2fa4..fc79e7ffc7 100644
--- a/src/crypto/rc4/rc4_asm.go
+++ b/src/crypto/rc4/rc4_asm.go
@@ -6,6 +6,8 @@
package rc4
+import "crypto/internal/subtle"
+
func xorKeyStream(dst, src *byte, n int, state *[256]uint32, i, j *uint8)
// XORKeyStream sets dst to the result of XORing src with the key stream.
@@ -14,7 +16,11 @@ func (c *Cipher) XORKeyStream(dst, src []byte) {
if len(src) == 0 {
return
}
- // Assert len(dst) >= len(src)
- _ = dst[len(src)-1]
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if subtle.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
xorKeyStream(&dst[0], &src[0], len(src), &c.s, &c.i, &c.j)
}
diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go
index f68dfc9999..26fdabb197 100644
--- a/src/crypto/rsa/boring_test.go
+++ b/src/crypto/rsa/boring_test.go
@@ -86,11 +86,11 @@ func TestBoringGenerateKey(t *testing.T) {
}
func TestBoringFinalizers(t *testing.T) {
- if runtime.GOOS == "nacl" {
- // Times out on nacl (without BoringCrypto)
+ if runtime.GOOS == "nacl" || runtime.GOOS == "js" {
+ // Times out on nacl and js/wasm (without BoringCrypto)
// but not clear why - probably consuming rand.Reader too quickly
// and being throttled. Also doesn't really matter.
- t.Skip("skipping on nacl")
+ t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
}
k, err := GenerateKey(rand.Reader, 2048)
diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go
index 340704aee2..446bf5d36e 100644
--- a/src/crypto/sha1/sha1block_s390x.go
+++ b/src/crypto/sha1/sha1block_s390x.go
@@ -4,9 +4,6 @@
package sha1
-// featureCheck reports whether the CPU supports the
-// SHA-1 compute intermediate message digest (KIMD)
-// function code.
-func featureCheck() bool
+import "internal/cpu"
-var useAsm = featureCheck()
+var useAsm = cpu.S390X.HasSHA1
diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s
index 3c71998645..6ba6883cc3 100644
--- a/src/crypto/sha1/sha1block_s390x.s
+++ b/src/crypto/sha1/sha1block_s390x.s
@@ -4,31 +4,17 @@
#include "textflag.h"
-// func featureCheck() bool
-TEXT ·featureCheck(SB),NOSPLIT,$16-1
- LA tmp-16(SP), R1
- XOR R0, R0 // query function code is 0
- WORD $0xB93E0006 // KIMD (R6 is ignored)
- MOVBZ tmp-16(SP), R4 // get the first byte
- AND $0x40, R4 // bit 1 (big endian) for SHA-1
- CMPBEQ R4, $0, nosha1
- MOVB $1, ret+0(FP)
- RET
-nosha1:
- MOVB $0, ret+0(FP)
- RET
-
// func block(dig *digest, p []byte)
-TEXT ·block(SB),NOSPLIT,$0-32
- MOVBZ ·useAsm(SB), R4
- LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
- CMPBNE R4, $1, generic
- MOVBZ $1, R0 // SHA-1 function code
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $1, R0 // SHA-1 function code
+ CMPBEQ R4, $0, generic
+
loop:
- WORD $0xB93E0002 // KIMD R2
- BVS loop // continue if interrupted
-done:
- XOR R0, R0 // restore R0
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
RET
+
generic:
- BR ·blockGeneric(SB)
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go
index b7beefef0c..1a376c5f93 100644
--- a/src/crypto/sha256/sha256block_s390x.go
+++ b/src/crypto/sha256/sha256block_s390x.go
@@ -4,9 +4,6 @@
package sha256
-// featureCheck reports whether the CPU supports the
-// SHA256 compute intermediate message digest (KIMD)
-// function code.
-func featureCheck() bool
+import "internal/cpu"
-var useAsm = featureCheck()
+var useAsm = cpu.S390X.HasSHA256
diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s
index ee35991f50..81b1b382c7 100644
--- a/src/crypto/sha256/sha256block_s390x.s
+++ b/src/crypto/sha256/sha256block_s390x.s
@@ -4,31 +4,17 @@
#include "textflag.h"
-// func featureCheck() bool
-TEXT ·featureCheck(SB),NOSPLIT,$16-1
- LA tmp-16(SP), R1
- XOR R0, R0 // query function code is 0
- WORD $0xB93E0006 // KIMD (R6 is ignored)
- MOVBZ tmp-16(SP), R4 // get the first byte
- AND $0x20, R4 // bit 2 (big endian) for SHA256
- CMPBEQ R4, $0, nosha256
- MOVB $1, ret+0(FP)
- RET
-nosha256:
- MOVB $0, ret+0(FP)
- RET
-
// func block(dig *digest, p []byte)
-TEXT ·block(SB),NOSPLIT,$0-32
- MOVBZ ·useAsm(SB), R4
- LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
- CMPBNE R4, $1, generic
- MOVBZ $2, R0 // SHA256 function code
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $2, R0 // SHA-256 function code
+ CMPBEQ R4, $0, generic
+
loop:
- WORD $0xB93E0002 // KIMD R2
- BVS loop // continue if interrupted
-done:
- XOR R0, R0 // restore R0
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
RET
+
generic:
- BR ·blockGeneric(SB)
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/sha512/sha512block_s390x.go b/src/crypto/sha512/sha512block_s390x.go
index f05dc18e12..7df29fd298 100644
--- a/src/crypto/sha512/sha512block_s390x.go
+++ b/src/crypto/sha512/sha512block_s390x.go
@@ -4,9 +4,6 @@
package sha512
-// featureCheck reports whether the CPU supports the
-// SHA512 compute intermediate message digest (KIMD)
-// function code.
-func featureCheck() bool
+import "internal/cpu"
-var useAsm = featureCheck()
+var useAsm = cpu.S390X.HasSHA512
diff --git a/src/crypto/sha512/sha512block_s390x.s b/src/crypto/sha512/sha512block_s390x.s
index aab81e2bcf..f221bd1399 100644
--- a/src/crypto/sha512/sha512block_s390x.s
+++ b/src/crypto/sha512/sha512block_s390x.s
@@ -4,31 +4,17 @@
#include "textflag.h"
-// func featureCheck() bool
-TEXT ·featureCheck(SB),NOSPLIT,$16-1
- LA tmp-16(SP), R1
- XOR R0, R0 // query function code is 0
- WORD $0xB93E0006 // KIMD (R6 is ignored)
- MOVBZ tmp-16(SP), R4 // get the first byte
- AND $0x10, R4 // bit 3 (big endian) for SHA512
- CMPBEQ R4, $0, nosha512
- MOVB $1, ret+0(FP)
- RET
-nosha512:
- MOVB $0, ret+0(FP)
- RET
-
// func block(dig *digest, p []byte)
-TEXT ·block(SB),NOSPLIT,$0-32
- MOVBZ ·useAsm(SB), R4
- LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
- CMPBNE R4, $1, generic
- MOVBZ $3, R0 // SHA512 function code
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $3, R0 // SHA-512 function code
+ CMPBEQ R4, $0, generic
+
loop:
- WORD $0xB93E0002 // KIMD R2
- BVS loop // continue if interrupted
-done:
- XOR R0, R0 // restore R0
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
RET
+
generic:
- BR ·blockGeneric(SB)
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go
new file mode 100644
index 0000000000..88face4cde
--- /dev/null
+++ b/src/crypto/tls/auth.go
@@ -0,0 +1,108 @@
+// Copyright 2017 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 tls
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/rsa"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+)
+
+// pickSignatureAlgorithm selects a signature algorithm that is compatible with
+// the given public key and the list of algorithms from the peer and this side.
+// The lists of signature algorithms (peerSigAlgs and ourSigAlgs) are ignored
+// for tlsVersion < VersionTLS12.
+//
+// The returned SignatureScheme codepoint is only meaningful for TLS 1.2,
+// previous TLS versions have a fixed hash function.
+func pickSignatureAlgorithm(pubkey crypto.PublicKey, peerSigAlgs, ourSigAlgs []SignatureScheme, tlsVersion uint16) (sigAlg SignatureScheme, sigType uint8, hashFunc crypto.Hash, err error) {
+ if tlsVersion < VersionTLS12 || len(peerSigAlgs) == 0 {
+ // For TLS 1.1 and before, the signature algorithm could not be
+ // negotiated and the hash is fixed based on the signature type.
+ // For TLS 1.2, if the client didn't send signature_algorithms
+ // extension then we can assume that it supports SHA1. See
+ // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
+ switch pubkey.(type) {
+ case *rsa.PublicKey:
+ if tlsVersion < VersionTLS12 {
+ return 0, signaturePKCS1v15, crypto.MD5SHA1, nil
+ } else {
+ return PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1, nil
+ }
+ case *ecdsa.PublicKey:
+ return ECDSAWithSHA1, signatureECDSA, crypto.SHA1, nil
+ default:
+ return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
+ }
+ }
+ for _, sigAlg := range peerSigAlgs {
+ if !isSupportedSignatureAlgorithm(sigAlg, ourSigAlgs) {
+ continue
+ }
+ hashAlg, err := lookupTLSHash(sigAlg)
+ if err != nil {
+ panic("tls: supported signature algorithm has an unknown hash function")
+ }
+ sigType := signatureFromSignatureScheme(sigAlg)
+ switch pubkey.(type) {
+ case *rsa.PublicKey:
+ if sigType == signaturePKCS1v15 || sigType == signatureRSAPSS {
+ return sigAlg, sigType, hashAlg, nil
+ }
+ case *ecdsa.PublicKey:
+ if sigType == signatureECDSA {
+ return sigAlg, sigType, hashAlg, nil
+ }
+ default:
+ return 0, 0, 0, fmt.Errorf("tls: unsupported public key: %T", pubkey)
+ }
+ }
+ return 0, 0, 0, errors.New("tls: peer doesn't support any common signature algorithms")
+}
+
+// verifyHandshakeSignature verifies a signature against pre-hashed handshake
+// contents.
+func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, digest, sig []byte) error {
+ switch sigType {
+ case signatureECDSA:
+ pubKey, ok := pubkey.(*ecdsa.PublicKey)
+ if !ok {
+ return errors.New("tls: ECDSA signing requires a ECDSA public key")
+ }
+ ecdsaSig := new(ecdsaSignature)
+ if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
+ return err
+ }
+ if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
+ return errors.New("tls: ECDSA signature contained zero or negative values")
+ }
+ if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
+ return errors.New("tls: ECDSA verification failure")
+ }
+ case signaturePKCS1v15:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return errors.New("tls: RSA signing requires a RSA public key")
+ }
+ if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
+ return err
+ }
+ case signatureRSAPSS:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return errors.New("tls: RSA signing requires a RSA public key")
+ }
+ signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+ if err := rsa.VerifyPSS(pubKey, hashFunc, digest, sig, signOpts); err != nil {
+ return err
+ }
+ default:
+ return errors.New("tls: unknown signature algorithm")
+ }
+ return nil
+}
diff --git a/src/crypto/tls/auth_test.go b/src/crypto/tls/auth_test.go
new file mode 100644
index 0000000000..3f876b9e1a
--- /dev/null
+++ b/src/crypto/tls/auth_test.go
@@ -0,0 +1,101 @@
+// Copyright 2017 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 tls
+
+import (
+ "crypto"
+ "testing"
+)
+
+func TestSignatureSelection(t *testing.T) {
+ rsaCert := &testRSAPrivateKey.PublicKey
+ ecdsaCert := &testECDSAPrivateKey.PublicKey
+ sigsPKCS1WithSHA := []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1}
+ sigsPSSWithSHA := []SignatureScheme{PSSWithSHA256, PSSWithSHA384}
+ sigsECDSAWithSHA := []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}
+
+ tests := []struct {
+ pubkey crypto.PublicKey
+ peerSigAlgs []SignatureScheme
+ ourSigAlgs []SignatureScheme
+ tlsVersion uint16
+
+ expectedSigAlg SignatureScheme // or 0 if ignored
+ expectedSigType uint8
+ expectedHash crypto.Hash
+ }{
+ // Hash is fixed for RSA in TLS 1.1 and before.
+ // https://tools.ietf.org/html/rfc4346#page-44
+ {rsaCert, nil, nil, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1},
+ {rsaCert, nil, nil, VersionTLS10, 0, signaturePKCS1v15, crypto.MD5SHA1},
+ {rsaCert, nil, nil, VersionSSL30, 0, signaturePKCS1v15, crypto.MD5SHA1},
+
+ // Before TLS 1.2, there is no signature_algorithms extension
+ // nor field in CertificateRequest and digitally-signed and thus
+ // it should be ignored.
+ {rsaCert, sigsPKCS1WithSHA, nil, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1},
+ {rsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signaturePKCS1v15, crypto.MD5SHA1},
+ // Use SHA-1 for TLS 1.0 and 1.1 with ECDSA, see https://tools.ietf.org/html/rfc4492#page-20
+ {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS11, 0, signatureECDSA, crypto.SHA1},
+ {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS10, 0, signatureECDSA, crypto.SHA1},
+
+ // TLS 1.2 without signature_algorithms extension
+ // https://tools.ietf.org/html/rfc5246#page-47
+ {rsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
+ {ecdsaCert, nil, sigsPKCS1WithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
+
+ {rsaCert, []SignatureScheme{PKCS1WithSHA1}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
+ {rsaCert, []SignatureScheme{PKCS1WithSHA256}, sigsPKCS1WithSHA, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
+ // "sha_hash" may denote hashes other than SHA-1
+ // https://tools.ietf.org/html/draft-ietf-tls-rfc4492bis-17#page-17
+ {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
+ {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, sigsECDSAWithSHA, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
+
+ // RSASSA-PSS is defined in TLS 1.3 for TLS 1.2
+ // https://tools.ietf.org/html/draft-ietf-tls-tls13-21#page-45
+ {rsaCert, []SignatureScheme{PSSWithSHA256}, sigsPSSWithSHA, VersionTLS12, PSSWithSHA256, signatureRSAPSS, crypto.SHA256},
+ }
+
+ for testNo, test := range tests {
+ sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion)
+ if err != nil {
+ t.Errorf("test[%d]: unexpected error: %v", testNo, err)
+ }
+ if test.expectedSigAlg != 0 && test.expectedSigAlg != sigAlg {
+ t.Errorf("test[%d]: expected signature scheme %#x, got %#x", testNo, test.expectedSigAlg, sigAlg)
+ }
+ if test.expectedSigType != sigType {
+ t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType)
+ }
+ if test.expectedHash != hashFunc {
+ t.Errorf("test[%d]: expected hash function %#x, got %#x", testNo, test.expectedHash, hashFunc)
+ }
+ }
+
+ badTests := []struct {
+ pubkey crypto.PublicKey
+ peerSigAlgs []SignatureScheme
+ ourSigAlgs []SignatureScheme
+ tlsVersion uint16
+ }{
+ {rsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12},
+ {ecdsaCert, sigsPKCS1WithSHA, sigsPKCS1WithSHA, VersionTLS12},
+ {ecdsaCert, sigsECDSAWithSHA, sigsPKCS1WithSHA, VersionTLS12},
+ {rsaCert, []SignatureScheme{0}, sigsPKCS1WithSHA, VersionTLS12},
+
+ // ECDSA is unspecified for SSL 3.0 in RFC 4492.
+ // TODO a SSL 3.0 client cannot advertise signature_algorithms,
+ // but if an application feeds an ECDSA certificate anyway, it
+ // will be accepted rather than trigger a handshake failure. Ok?
+ //{ecdsaCert, nil, nil, VersionSSL30},
+ }
+
+ for testNo, test := range badTests {
+ sigAlg, sigType, hashFunc, err := pickSignatureAlgorithm(test.pubkey, test.peerSigAlgs, test.ourSigAlgs, test.tlsVersion)
+ if err == nil {
+ t.Errorf("test[%d]: unexpected success, got %#x %#x %#x", testNo, sigAlg, sigType, hashFunc)
+ }
+ }
+}
diff --git a/src/crypto/tls/boring_test.go b/src/crypto/tls/boring_test.go
index f31f3f6bc8..2ac62a5540 100644
--- a/src/crypto/tls/boring_test.go
+++ b/src/crypto/tls/boring_test.go
@@ -274,8 +274,8 @@ func TestBoringClientHello(t *testing.T) {
}
func TestBoringCertAlgs(t *testing.T) {
- // NaCl and arm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
- if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" {
+ // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
+ if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" {
t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH)
}
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
index 9c38463bf8..e4027e8ab4 100644
--- a/src/crypto/tls/cipher_suites.go
+++ b/src/crypto/tls/cipher_suites.go
@@ -353,14 +353,14 @@ func rsaKA(version uint16) keyAgreement {
func ecdheECDSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{
- sigType: signatureECDSA,
+ isRSA: false,
version: version,
}
}
func ecdheRSAKA(version uint16) keyAgreement {
return &ecdheKeyAgreement{
- sigType: signatureRSA,
+ isRSA: true,
version: version,
}
}
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index a76e4efac0..9a63eef571 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -128,10 +128,12 @@ const (
// Rest of these are reserved by the TLS spec
)
-// Signature algorithms for TLS 1.2 (See RFC 5246, section A.4.1)
+// Signature algorithms (for internal signaling use). Starting at 16 to avoid overlap with
+// TLS 1.2 codepoints (RFC 5246, section A.4.1), with which these have nothing to do.
const (
- signatureRSA uint8 = 1
- signatureECDSA uint8 = 3
+ signaturePKCS1v15 uint8 = iota + 16
+ signatureECDSA
+ signatureRSAPSS
)
// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
@@ -943,7 +945,8 @@ func initDefaultCipherSuites() {
hasGCMAsmARM64 := false
// hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
- hasGCMAsmS390X := cpu.S390X.HasKM && (cpu.S390X.HasKMA || (cpu.S390X.HasKMCTR && cpu.S390X.HasKIMD))
+ // Keep in sync with crypto/aes/cipher_s390x.go.
+ hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
@@ -1007,7 +1010,9 @@ func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlg
func signatureFromSignatureScheme(signatureAlgorithm SignatureScheme) uint8 {
switch signatureAlgorithm {
case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
- return signatureRSA
+ return signaturePKCS1v15
+ case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
+ return signatureRSAPSS
case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
return signatureECDSA
default:
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index 752f9a9293..b32f240a09 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -484,31 +484,25 @@ func (hs *clientHandshakeState) doFullHandshake() error {
return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
}
- var signatureType uint8
- switch key.Public().(type) {
- case *ecdsa.PublicKey:
- signatureType = signatureECDSA
- case *rsa.PublicKey:
- signatureType = signatureRSA
- default:
+ signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(key.Public(), certReq.supportedSignatureAlgorithms, hs.hello.supportedSignatureAlgorithms, c.vers)
+ if err != nil {
c.sendAlert(alertInternalError)
- return fmt.Errorf("tls: failed to sign handshake with client certificate: unknown client certificate key type: %T", key)
+ return err
}
-
// SignatureAndHashAlgorithm was introduced in TLS 1.2.
if certVerify.hasSignatureAndHash {
- certVerify.signatureAlgorithm, err = hs.finishedHash.selectClientCertSignatureAlgorithm(certReq.supportedSignatureAlgorithms, signatureType)
- if err != nil {
- c.sendAlert(alertInternalError)
- return err
- }
+ certVerify.signatureAlgorithm = signatureAlgorithm
}
- digest, hashFunc, err := hs.finishedHash.hashForClientCertificate(signatureType, certVerify.signatureAlgorithm, hs.masterSecret)
+ digest, err := hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret)
if err != nil {
c.sendAlert(alertInternalError)
return err
}
- certVerify.signature, err = key.Sign(c.config.rand(), digest, hashFunc)
+ signOpts := crypto.SignerOpts(hashFunc)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
+ }
+ certVerify.signature, err = key.Sign(c.config.rand(), digest, signOpts)
if err != nil {
c.sendAlert(alertInternalError)
return err
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index cc3ab714a6..2ab4e474ec 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -1578,3 +1578,42 @@ func TestGetClientCertificate(t *testing.T) {
}
}
}
+
+func TestRSAPSSKeyError(t *testing.T) {
+ // crypto/tls does not support the rsa_pss_pss_xxx SignatureSchemes. If support for
+ // public keys with OID RSASSA-PSS is added to crypto/x509, they will be misused with
+ // the rsa_pss_rsae_xxx SignatureSchemes. Assert that RSASSA-PSS certificates don't
+ // parse, or that they don't carry *rsa.PublicKey keys.
+ b, _ := pem.Decode([]byte(`
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAhygAwIBAgIUCF2x0FyTgZG0CC9QTDjGWkB5vgEwPgYJKoZIhvcNAQEK
+MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC
+AgDeMBIxEDAOBgNVBAMMB1JTQS1QU1MwHhcNMTgwNjI3MjI0NDM2WhcNMTgwNzI3
+MjI0NDM2WjASMRAwDgYDVQQDDAdSU0EtUFNTMIIBIDALBgkqhkiG9w0BAQoDggEP
+ADCCAQoCggEBANxDm0f76JdI06YzsjB3AmmjIYkwUEGxePlafmIASFjDZl/elD0Z
+/a7xLX468b0qGxLS5al7XCcEprSdsDR6DF5L520+pCbpfLyPOjuOvGmk9KzVX4x5
+b05YXYuXdsQ0Kjxcx2i3jjCday6scIhMJVgBZxTEyMj1thPQM14SHzKCd/m6HmCL
+QmswpH2yMAAcBRWzRpp/vdH5DeOJEB3aelq7094no731mrLUCHRiZ1htq8BDB3ou
+czwqgwspbqZ4dnMXl2MvfySQ5wJUxQwILbiuAKO2lVVPUbFXHE9pgtznNoPvKwQT
+JNcX8ee8WIZc2SEGzofjk3NpjR+2ADB2u3sCAwEAAaNTMFEwHQYDVR0OBBYEFNEz
+AdyJ2f+fU+vSCS6QzohnOnprMB8GA1UdIwQYMBaAFNEzAdyJ2f+fU+vSCS6Qzohn
+OnprMA8GA1UdEwEB/wQFMAMBAf8wPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQME
+AgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQCAgDeA4IBAQCjEdrR5aab
+sZmCwrMeKidXgfkmWvfuLDE+TCbaqDZp7BMWcMQXT9O0UoUT5kqgKj2ARm2pEW0Z
+H3Z1vj3bbds72qcDIJXp+l0fekyLGeCrX/CbgnMZXEP7+/+P416p34ChR1Wz4dU1
+KD3gdsUuTKKeMUog3plxlxQDhRQmiL25ygH1LmjLd6dtIt0GVRGr8lj3euVeprqZ
+bZ3Uq5eLfsn8oPgfC57gpO6yiN+UURRTlK3bgYvLh4VWB3XXk9UaQZ7Mq1tpXjoD
+HYFybkWzibkZp4WRo+Fa28rirH+/wHt0vfeN7UCceURZEx4JaxIIfe4ku7uDRhJi
+RwBA9Xk1KBNF
+-----END CERTIFICATE-----`))
+ if b == nil {
+ t.Fatal("Failed to decode certificate")
+ }
+ cert, err := x509.ParseCertificate(b.Bytes)
+ if err != nil {
+ return
+ }
+ if _, ok := cert.PublicKey.(*rsa.PublicKey); ok {
+ t.Error("A RSA-PSS certificate was parsed like a PKCS1 one, and it will be mistakenly used with rsa_pss_rsae_xxx signature algorithms")
+ }
+}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 5b1aa64166..c5caab1224 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -10,7 +10,6 @@ import (
"crypto/rsa"
"crypto/subtle"
"crypto/x509"
- "encoding/asn1"
"errors"
"fmt"
"io"
@@ -520,59 +519,15 @@ func (hs *serverHandshakeState) doFullHandshake() error {
}
// Determine the signature type.
- var signatureAlgorithm SignatureScheme
- var sigType uint8
- if certVerify.hasSignatureAndHash {
- signatureAlgorithm = certVerify.signatureAlgorithm
- if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms()) {
- return errors.New("tls: unsupported hash function for client certificate")
- }
- sigType = signatureFromSignatureScheme(signatureAlgorithm)
- } else {
- // Before TLS 1.2 the signature algorithm was implicit
- // from the key type, and only one hash per signature
- // algorithm was possible. Leave signatureAlgorithm
- // unset.
- switch pub.(type) {
- case *ecdsa.PublicKey:
- sigType = signatureECDSA
- case *rsa.PublicKey:
- sigType = signatureRSA
- }
+ _, sigType, hashFunc, err := pickSignatureAlgorithm(pub, []SignatureScheme{certVerify.signatureAlgorithm}, supportedSignatureAlgorithms(), c.vers)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
}
- switch key := pub.(type) {
- case *ecdsa.PublicKey:
- if sigType != signatureECDSA {
- err = errors.New("tls: bad signature type for client's ECDSA certificate")
- break
- }
- ecdsaSig := new(ecdsaSignature)
- if _, err = asn1.Unmarshal(certVerify.signature, ecdsaSig); err != nil {
- break
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- err = errors.New("tls: ECDSA signature contained zero or negative values")
- break
- }
- var digest []byte
- if digest, _, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil {
- break
- }
- if !ecdsa.Verify(key, digest, ecdsaSig.R, ecdsaSig.S) {
- err = errors.New("tls: ECDSA verification failure")
- }
- case *rsa.PublicKey:
- if sigType != signatureRSA {
- err = errors.New("tls: bad signature type for client's RSA certificate")
- break
- }
- var digest []byte
- var hashFunc crypto.Hash
- if digest, hashFunc, err = hs.finishedHash.hashForClientCertificate(sigType, signatureAlgorithm, hs.masterSecret); err != nil {
- break
- }
- err = rsa.VerifyPKCS1v15(key, hashFunc, digest, certVerify.signature)
+ var digest []byte
+ if digest, err = hs.finishedHash.hashForClientCertificate(sigType, hashFunc, hs.masterSecret); err == nil {
+ err = verifyHandshakeSignature(sigType, pub, hashFunc, digest, certVerify.signature)
}
if err != nil {
c.sendAlert(alertBadCertificate)
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
index 5d6dc21c6d..0754d1b389 100644
--- a/src/crypto/tls/key_agreement.go
+++ b/src/crypto/tls/key_agreement.go
@@ -6,13 +6,11 @@ package tls
import (
"crypto"
- "crypto/ecdsa"
"crypto/elliptic"
"crypto/md5"
"crypto/rsa"
"crypto/sha1"
"crypto/x509"
- "encoding/asn1"
"errors"
"io"
"math/big"
@@ -110,58 +108,21 @@ func md5SHA1Hash(slices [][]byte) []byte {
}
// hashForServerKeyExchange hashes the given slices and returns their digest
-// and the identifier of the hash function used. The signatureAlgorithm argument
-// is only used for >= TLS 1.2 and identifies the hash function to use.
-func hashForServerKeyExchange(sigType uint8, signatureAlgorithm SignatureScheme, version uint16, slices ...[]byte) ([]byte, crypto.Hash, error) {
+// using the given hash function (for >= TLS 1.2) or using a default based on
+// the sigType (for earlier TLS versions).
+func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) ([]byte, error) {
if version >= VersionTLS12 {
- if !isSupportedSignatureAlgorithm(signatureAlgorithm, supportedSignatureAlgorithms()) {
- return nil, crypto.Hash(0), errors.New("tls: unsupported hash function used by peer")
- }
- hashFunc, err := lookupTLSHash(signatureAlgorithm)
- if err != nil {
- return nil, crypto.Hash(0), err
- }
h := hashFunc.New()
for _, slice := range slices {
h.Write(slice)
}
digest := h.Sum(nil)
- return digest, hashFunc, nil
+ return digest, nil
}
if sigType == signatureECDSA {
- return sha1Hash(slices), crypto.SHA1, nil
- }
- return md5SHA1Hash(slices), crypto.MD5SHA1, nil
-}
-
-// pickTLS12HashForSignature returns a TLS 1.2 hash identifier for signing a
-// ServerKeyExchange given the signature type being used and the client's
-// advertised list of supported signature and hash combinations.
-func pickTLS12HashForSignature(sigType uint8, clientList []SignatureScheme) (SignatureScheme, error) {
- if len(clientList) == 0 {
- // If the client didn't specify any signature_algorithms
- // extension then we can assume that it supports SHA1. See
- // https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1
- switch sigType {
- case signatureRSA:
- return PKCS1WithSHA1, nil
- case signatureECDSA:
- return ECDSAWithSHA1, nil
- default:
- return 0, errors.New("tls: unknown signature algorithm")
- }
+ return sha1Hash(slices), nil
}
-
- for _, sigAlg := range clientList {
- if signatureFromSignatureScheme(sigAlg) != sigType {
- continue
- }
- if isSupportedSignatureAlgorithm(sigAlg, supportedSignatureAlgorithms()) {
- return sigAlg, nil
- }
- }
-
- return 0, errors.New("tls: client doesn't support any common hash functions")
+ return md5SHA1Hash(slices), nil
}
func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
@@ -178,13 +139,13 @@ func curveForCurveID(id CurveID) (elliptic.Curve, bool) {
}
-// ecdheRSAKeyAgreement implements a TLS key agreement where the server
+// ecdheKeyAgreement implements a TLS key agreement where the server
// generates an ephemeral EC public/private key pair and signs it. The
// pre-master secret is then calculated using ECDH. The signature may
// either be ECDSA or RSA.
type ecdheKeyAgreement struct {
version uint16
- sigType uint8
+ isRSA bool
privateKey []byte
curveid CurveID
@@ -247,41 +208,29 @@ NextCandidate:
serverECDHParams[3] = byte(len(ecdhePublic))
copy(serverECDHParams[4:], ecdhePublic)
- var signatureAlgorithm SignatureScheme
-
- if ka.version >= VersionTLS12 {
- var err error
- signatureAlgorithm, err = pickTLS12HashForSignature(ka.sigType, clientHello.supportedSignatureAlgorithms)
- if err != nil {
- return nil, err
- }
+ priv, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
}
- digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, hello.random, serverECDHParams)
+ signatureAlgorithm, sigType, hashFunc, err := pickSignatureAlgorithm(priv.Public(), clientHello.supportedSignatureAlgorithms, supportedSignatureAlgorithms(), ka.version)
if err != nil {
return nil, err
}
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
+ }
- priv, ok := cert.PrivateKey.(crypto.Signer)
- if !ok {
- return nil, errors.New("tls: certificate private key does not implement crypto.Signer")
+ digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, hello.random, serverECDHParams)
+ if err != nil {
+ return nil, err
}
- var sig []byte
- switch ka.sigType {
- case signatureECDSA:
- _, ok := priv.Public().(*ecdsa.PublicKey)
- if !ok {
- return nil, errors.New("tls: ECDHE ECDSA requires an ECDSA server key")
- }
- case signatureRSA:
- _, ok := priv.Public().(*rsa.PublicKey)
- if !ok {
- return nil, errors.New("tls: ECDHE RSA requires a RSA server key")
- }
- default:
- return nil, errors.New("tls: unknown ECDHE signature algorithm")
+
+ signOpts := crypto.SignerOpts(hashFunc)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: hashFunc}
}
- sig, err = priv.Sign(config.rand(), digest, hashFunc)
+ sig, err := priv.Sign(config.rand(), digest, signOpts)
if err != nil {
return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
}
@@ -380,53 +329,30 @@ func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHell
if ka.version >= VersionTLS12 {
// handle SignatureAndHashAlgorithm
signatureAlgorithm = SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
- if signatureFromSignatureScheme(signatureAlgorithm) != ka.sigType {
- return errServerKeyExchange
- }
sig = sig[2:]
if len(sig) < 2 {
return errServerKeyExchange
}
}
+ _, sigType, hashFunc, err := pickSignatureAlgorithm(cert.PublicKey, []SignatureScheme{signatureAlgorithm}, clientHello.supportedSignatureAlgorithms, ka.version)
+ if err != nil {
+ return err
+ }
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return errServerKeyExchange
+ }
+
sigLen := int(sig[0])<<8 | int(sig[1])
if sigLen+2 != len(sig) {
return errServerKeyExchange
}
sig = sig[2:]
- digest, hashFunc, err := hashForServerKeyExchange(ka.sigType, signatureAlgorithm, ka.version, clientHello.random, serverHello.random, serverECDHParams)
+ digest, err := hashForServerKeyExchange(sigType, hashFunc, ka.version, clientHello.random, serverHello.random, serverECDHParams)
if err != nil {
return err
}
- switch ka.sigType {
- case signatureECDSA:
- pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey)
- if !ok {
- return errors.New("tls: ECDHE ECDSA requires a ECDSA server public key")
- }
- ecdsaSig := new(ecdsaSignature)
- if _, err := asn1.Unmarshal(sig, ecdsaSig); err != nil {
- return err
- }
- if ecdsaSig.R.Sign() <= 0 || ecdsaSig.S.Sign() <= 0 {
- return errors.New("tls: ECDSA signature contained zero or negative values")
- }
- if !ecdsa.Verify(pubKey, digest, ecdsaSig.R, ecdsaSig.S) {
- return errors.New("tls: ECDSA verification failure")
- }
- case signatureRSA:
- pubKey, ok := cert.PublicKey.(*rsa.PublicKey)
- if !ok {
- return errors.New("tls: ECDHE RSA requires a RSA server public key")
- }
- if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, digest, sig); err != nil {
- return err
- }
- default:
- return errors.New("tls: unknown ECDHE signature algorithm")
- }
-
- return nil
+ return verifyHandshakeSignature(sigType, cert.PublicKey, hashFunc, digest, sig)
}
func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
index 8246cd3484..98e9ab4292 100644
--- a/src/crypto/tls/prf.go
+++ b/src/crypto/tls/prf.go
@@ -309,50 +309,35 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte {
return out
}
-// selectClientCertSignatureAlgorithm returns a SignatureScheme to sign a
-// client's CertificateVerify with, or an error if none can be found.
-func (h finishedHash) selectClientCertSignatureAlgorithm(serverList []SignatureScheme, sigType uint8) (SignatureScheme, error) {
- for _, v := range serverList {
- if signatureFromSignatureScheme(v) == sigType && isSupportedSignatureAlgorithm(v, supportedSignatureAlgorithms()) {
- return v, nil
- }
- }
- return 0, errors.New("tls: no supported signature algorithm found for signing client certificate")
-}
-
-// hashForClientCertificate returns a digest, hash function, and TLS 1.2 hash
-// id suitable for signing by a TLS client certificate.
-func (h finishedHash) hashForClientCertificate(sigType uint8, signatureAlgorithm SignatureScheme, masterSecret []byte) ([]byte, crypto.Hash, error) {
+// hashForClientCertificate returns a digest over the handshake messages so far,
+// suitable for signing by a TLS client certificate.
+func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash, masterSecret []byte) ([]byte, error) {
if (h.version == VersionSSL30 || h.version >= VersionTLS12) && h.buffer == nil {
panic("a handshake hash for a client-certificate was requested after discarding the handshake buffer")
}
if h.version == VersionSSL30 {
- if sigType != signatureRSA {
- return nil, 0, errors.New("tls: unsupported signature type for client certificate")
+ if sigType != signaturePKCS1v15 {
+ return nil, errors.New("tls: unsupported signature type for client certificate")
}
md5Hash := md5.New()
md5Hash.Write(h.buffer)
sha1Hash := sha1.New()
sha1Hash.Write(h.buffer)
- return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), crypto.MD5SHA1, nil
+ return finishedSum30(md5Hash, sha1Hash, masterSecret, nil), nil
}
if h.version >= VersionTLS12 {
- hashAlg, err := lookupTLSHash(signatureAlgorithm)
- if err != nil {
- return nil, 0, err
- }
hash := hashAlg.New()
hash.Write(h.buffer)
- return hash.Sum(nil), hashAlg, nil
+ return hash.Sum(nil), nil
}
if sigType == signatureECDSA {
- return h.server.Sum(nil), crypto.SHA1, nil
+ return h.server.Sum(nil), nil
}
- return h.Sum(), crypto.MD5SHA1, nil
+ return h.Sum(), nil
}
// discardHandshakeBuffer is called when there is no more need to
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
index bc35a1cf21..9d7b3a6ffb 100644
--- a/src/crypto/x509/root_darwin.go
+++ b/src/crypto/x509/root_darwin.go
@@ -181,12 +181,12 @@ func verifyCertWithSystem(block *pem.Block, cert *Certificate) bool {
}
if err := cmd.Run(); err != nil {
if debugExecDarwinRoots {
- println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject.CommonName, bytes.TrimSpace(stderr.Bytes())))
+ println(fmt.Sprintf("crypto/x509: verify-cert rejected %s: %q", cert.Subject, bytes.TrimSpace(stderr.Bytes())))
}
return false
}
if debugExecDarwinRoots {
- println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject.CommonName))
+ println(fmt.Sprintf("crypto/x509: verify-cert approved %s", cert.Subject))
}
return true
}
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index d935cc4e9a..2784ce2f0f 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -16,11 +16,6 @@ func TestSystemRoots(t *testing.T) {
t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
}
- switch runtime.GOOS {
- case "darwin":
- t.Skipf("skipping on %s/%s until cgo part of golang.org/issue/16532 has been implemented.", runtime.GOOS, runtime.GOARCH)
- }
-
t0 := time.Now()
sysRoots := systemRootsPool() // actual system roots
sysRootsDuration := time.Since(t0)
diff --git a/src/debug/elf/file.go b/src/debug/elf/file.go
index 25b72642d8..b2adc2834f 100644
--- a/src/debug/elf/file.go
+++ b/src/debug/elf/file.go
@@ -1112,6 +1112,17 @@ func (f *File) applyRelocationsSPARC64(dst []byte, rels []byte) error {
}
func (f *File) DWARF() (*dwarf.Data, error) {
+ dwarfSuffix := func(s *Section) string {
+ switch {
+ case strings.HasPrefix(s.Name, ".debug_"):
+ return s.Name[7:]
+ case strings.HasPrefix(s.Name, ".zdebug_"):
+ return s.Name[8:]
+ default:
+ return ""
+ }
+
+ }
// sectionData gets the data for s, checks its size, and
// applies any applicable relations.
sectionData := func(i int, s *Section) ([]byte, error) {
@@ -1160,13 +1171,8 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// Don't bother loading others.
var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
for i, s := range f.Sections {
- suffix := ""
- switch {
- case strings.HasPrefix(s.Name, ".debug_"):
- suffix = s.Name[7:]
- case strings.HasPrefix(s.Name, ".zdebug_"):
- suffix = s.Name[8:]
- default:
+ suffix := dwarfSuffix(s)
+ if suffix == "" {
continue
}
if _, ok := dat[suffix]; !ok {
@@ -1186,16 +1192,19 @@ func (f *File) DWARF() (*dwarf.Data, error) {
// Look for DWARF4 .debug_types sections.
for i, s := range f.Sections {
- if s.Name == ".debug_types" {
- b, err := sectionData(i, s)
- if err != nil {
- return nil, err
- }
+ suffix := dwarfSuffix(s)
+ if suffix != "types" {
+ continue
+ }
- err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
- if err != nil {
- return nil, err
- }
+ b, err := sectionData(i, s)
+ if err != nil {
+ return nil, err
+ }
+
+ err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+ if err != nil {
+ return nil, err
}
}
diff --git a/src/debug/macho/file.go b/src/debug/macho/file.go
index da5d9cad4c..16708e5247 100644
--- a/src/debug/macho/file.go
+++ b/src/debug/macho/file.go
@@ -9,11 +9,13 @@ package macho
import (
"bytes"
+ "compress/zlib"
"debug/dwarf"
"encoding/binary"
"fmt"
"io"
"os"
+ "strings"
)
// A File represents an open Mach-O file.
@@ -575,26 +577,84 @@ func (f *File) Section(name string) *Section {
// DWARF returns the DWARF debug information for the Mach-O file.
func (f *File) DWARF() (*dwarf.Data, error) {
+ dwarfSuffix := func(s *Section) string {
+ switch {
+ case strings.HasPrefix(s.Name, "__debug_"):
+ return s.Name[8:]
+ case strings.HasPrefix(s.Name, "__zdebug_"):
+ return s.Name[9:]
+ default:
+ return ""
+ }
+
+ }
+ sectionData := func(s *Section) ([]byte, error) {
+ b, err := s.Data()
+ if err != nil && uint64(len(b)) < s.Size {
+ return nil, err
+ }
+
+ if len(b) >= 12 && string(b[:4]) == "ZLIB" {
+ dlen := binary.BigEndian.Uint64(b[4:12])
+ dbuf := make([]byte, dlen)
+ r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
+ if err != nil {
+ return nil, err
+ }
+ if _, err := io.ReadFull(r, dbuf); err != nil {
+ return nil, err
+ }
+ if err := r.Close(); err != nil {
+ return nil, err
+ }
+ b = dbuf
+ }
+ return b, nil
+ }
+
// There are many other DWARF sections, but these
// are the ones the debug/dwarf package uses.
// Don't bother loading others.
- var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
- var dat [len(names)][]byte
- for i, name := range names {
- name = "__debug_" + name
- s := f.Section(name)
- if s == nil {
+ var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
+ for _, s := range f.Sections {
+ suffix := dwarfSuffix(s)
+ if suffix == "" {
continue
}
- b, err := s.Data()
- if err != nil && uint64(len(b)) < s.Size {
+ if _, ok := dat[suffix]; !ok {
+ continue
+ }
+ b, err := sectionData(s)
+ if err != nil {
+ return nil, err
+ }
+ dat[suffix] = b
+ }
+
+ d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
+ if err != nil {
+ return nil, err
+ }
+
+ // Look for DWARF4 .debug_types sections.
+ for i, s := range f.Sections {
+ suffix := dwarfSuffix(s)
+ if suffix != "types" {
+ continue
+ }
+
+ b, err := sectionData(s)
+ if err != nil {
+ return nil, err
+ }
+
+ err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+ if err != nil {
return nil, err
}
- dat[i] = b
}
- abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
- return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ return d, nil
}
// ImportedSymbols returns the names of all symbols
diff --git a/src/debug/pe/file.go b/src/debug/pe/file.go
index 6fc1f3a60f..2f5efae4e6 100644
--- a/src/debug/pe/file.go
+++ b/src/debug/pe/file.go
@@ -6,11 +6,14 @@
package pe
import (
+ "bytes"
+ "compress/zlib"
"debug/dwarf"
"encoding/binary"
"fmt"
"io"
"os"
+ "strings"
)
// Avoid use of post-Go 1.4 io features, to make safe for toolchain bootstrap.
@@ -217,29 +220,91 @@ func (f *File) Section(name string) *Section {
}
func (f *File) DWARF() (*dwarf.Data, error) {
- // There are many other DWARF sections, but these
- // are the ones the debug/dwarf package uses.
- // Don't bother loading others.
- var names = [...]string{"abbrev", "info", "line", "ranges", "str"}
- var dat [len(names)][]byte
- for i, name := range names {
- name = ".debug_" + name
- s := f.Section(name)
- if s == nil {
- continue
+ dwarfSuffix := func(s *Section) string {
+ switch {
+ case strings.HasPrefix(s.Name, ".debug_"):
+ return s.Name[7:]
+ case strings.HasPrefix(s.Name, ".zdebug_"):
+ return s.Name[8:]
+ default:
+ return ""
}
+
+ }
+
+ // sectionData gets the data for s and checks its size.
+ sectionData := func(s *Section) ([]byte, error) {
b, err := s.Data()
if err != nil && uint32(len(b)) < s.Size {
return nil, err
}
+
if 0 < s.VirtualSize && s.VirtualSize < s.Size {
b = b[:s.VirtualSize]
}
- dat[i] = b
+
+ if len(b) >= 12 && string(b[:4]) == "ZLIB" {
+ dlen := binary.BigEndian.Uint64(b[4:12])
+ dbuf := make([]byte, dlen)
+ r, err := zlib.NewReader(bytes.NewBuffer(b[12:]))
+ if err != nil {
+ return nil, err
+ }
+ if _, err := io.ReadFull(r, dbuf); err != nil {
+ return nil, err
+ }
+ if err := r.Close(); err != nil {
+ return nil, err
+ }
+ b = dbuf
+ }
+ return b, nil
+ }
+
+ // There are many other DWARF sections, but these
+ // are the ones the debug/dwarf package uses.
+ // Don't bother loading others.
+ var dat = map[string][]byte{"abbrev": nil, "info": nil, "str": nil, "line": nil, "ranges": nil}
+ for _, s := range f.Sections {
+ suffix := dwarfSuffix(s)
+ if suffix == "" {
+ continue
+ }
+ if _, ok := dat[suffix]; !ok {
+ continue
+ }
+
+ b, err := sectionData(s)
+ if err != nil {
+ return nil, err
+ }
+ dat[suffix] = b
+ }
+
+ d, err := dwarf.New(dat["abbrev"], nil, nil, dat["info"], dat["line"], nil, dat["ranges"], dat["str"])
+ if err != nil {
+ return nil, err
+ }
+
+ // Look for DWARF4 .debug_types sections.
+ for i, s := range f.Sections {
+ suffix := dwarfSuffix(s)
+ if suffix != "types" {
+ continue
+ }
+
+ b, err := sectionData(s)
+ if err != nil {
+ return nil, err
+ }
+
+ err = d.AddTypes(fmt.Sprintf("types-%d", i), b)
+ if err != nil {
+ return nil, err
+ }
}
- abbrev, info, line, ranges, str := dat[0], dat[1], dat[2], dat[3], dat[4]
- return dwarf.New(abbrev, nil, nil, info, line, nil, ranges, str)
+ return d, nil
}
// TODO(brainman): document ImportDirectory once we decide what to do with it.
diff --git a/src/encoding/base32/base32.go b/src/encoding/base32/base32.go
index 60f25b04b2..3fb6caceab 100644
--- a/src/encoding/base32/base32.go
+++ b/src/encoding/base32/base32.go
@@ -21,7 +21,7 @@ import (
// introduced for SASL GSSAPI and standardized in RFC 4648.
// The alternate "base32hex" encoding is used in DNSSEC.
type Encoding struct {
- encode string
+ encode [32]byte
decodeMap [256]byte
padChar rune
}
@@ -37,8 +37,12 @@ const encodeHex = "0123456789ABCDEFGHIJKLMNOPQRSTUV"
// NewEncoding returns a new Encoding defined by the given alphabet,
// which must be a 32-byte string.
func NewEncoding(encoder string) *Encoding {
+ if len(encoder) != 32 {
+ panic("encoding alphabet is not 32-bytes long")
+ }
+
e := new(Encoding)
- e.encode = encoder
+ copy(e.encode[:], encoder)
e.padChar = StdPadding
for i := 0; i < len(e.decodeMap); i++ {
@@ -129,17 +133,17 @@ func (enc *Encoding) Encode(dst, src []byte) {
size := len(dst)
if size >= 8 {
// Common case, unrolled for extra performance
- dst[0] = enc.encode[b[0]]
- dst[1] = enc.encode[b[1]]
- dst[2] = enc.encode[b[2]]
- dst[3] = enc.encode[b[3]]
- dst[4] = enc.encode[b[4]]
- dst[5] = enc.encode[b[5]]
- dst[6] = enc.encode[b[6]]
- dst[7] = enc.encode[b[7]]
+ dst[0] = enc.encode[b[0]&31]
+ dst[1] = enc.encode[b[1]&31]
+ dst[2] = enc.encode[b[2]&31]
+ dst[3] = enc.encode[b[3]&31]
+ dst[4] = enc.encode[b[4]&31]
+ dst[5] = enc.encode[b[5]&31]
+ dst[6] = enc.encode[b[6]&31]
+ dst[7] = enc.encode[b[7]&31]
} else {
for i := 0; i < size; i++ {
- dst[i] = enc.encode[b[i]]
+ dst[i] = enc.encode[b[i]&31]
}
}
diff --git a/src/encoding/gob/encoder_test.go b/src/encoding/gob/encoder_test.go
index a41fc9e889..dc9bbcf35d 100644
--- a/src/encoding/gob/encoder_test.go
+++ b/src/encoding/gob/encoder_test.go
@@ -1015,7 +1015,7 @@ type Bug4Secret struct {
}
// Test that a failed compilation doesn't leave around an executable encoder.
-// Issue 3273.
+// Issue 3723.
func TestMutipleEncodingsOfBadType(t *testing.T) {
x := Bug4Public{
Name: "name",
diff --git a/src/flag/example_value_test.go b/src/flag/example_value_test.go
new file mode 100644
index 0000000000..9d464c62e8
--- /dev/null
+++ b/src/flag/example_value_test.go
@@ -0,0 +1,44 @@
+// Copyright 2018 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 flag_test
+
+import (
+ "flag"
+ "fmt"
+ "net/url"
+)
+
+type URLValue struct {
+ URL *url.URL
+}
+
+func (v URLValue) String() string {
+ if v.URL != nil {
+ return v.URL.String()
+ }
+ return ""
+}
+
+func (v URLValue) Set(s string) error {
+ if u, err := url.Parse(s); err != nil {
+ return err
+ } else {
+ *v.URL = *u
+ }
+ return nil
+}
+
+var u = &url.URL{}
+
+func ExampleValue() {
+ fs := flag.NewFlagSet("ExampleValue", flag.ExitOnError)
+ fs.Var(&URLValue{u}, "url", "URL to parse")
+
+ fs.Parse([]string{"-url", "https://golang.org/pkg/flag/"})
+ fmt.Printf(`{scheme: %q, host: %q, path: %q}`, u.Scheme, u.Host, u.Path)
+
+ // Output:
+ // {scheme: "https", host: "golang.org", path: "/pkg/flag/"}
+}
diff --git a/src/flag/flag.go b/src/flag/flag.go
index 188adb285f..2cd7829c1a 100644
--- a/src/flag/flag.go
+++ b/src/flag/flag.go
@@ -36,6 +36,9 @@
The arguments are indexed from 0 through flag.NArg()-1.
Command line flag syntax
+
+ The following forms are permitted:
+
-flag
-flag=x
-flag x // non-boolean flags only
diff --git a/src/go/ast/ast.go b/src/go/ast/ast.go
index d73c323178..fd109507b8 100644
--- a/src/go/ast/ast.go
+++ b/src/go/ast/ast.go
@@ -153,10 +153,12 @@ func (g *CommentGroup) Text() string {
// A Field represents a Field declaration list in a struct type,
// a method list in an interface type, or a parameter/result declaration
// in a signature.
+// Field.Names is nil for unnamed parameters (parameter lists which only contain types)
+// and embedded struct fields. In the latter case, the field name is the type name.
//
type Field struct {
Doc *CommentGroup // associated documentation; or nil
- Names []*Ident // field/method/parameter names; or nil if anonymous field
+ Names []*Ident // field/method/parameter names; or nil
Type Expr // field/method/parameter type
Tag *BasicLit // field tag; or nil
Comment *CommentGroup // line comments; or nil
@@ -207,14 +209,14 @@ func (f *FieldList) End() token.Pos {
return token.NoPos
}
-// NumFields returns the number of (named and anonymous fields) in a FieldList.
+// NumFields returns the number of parameters or struct fields represented by a FieldList.
func (f *FieldList) NumFields() int {
n := 0
if f != nil {
for _, g := range f.List {
m := len(g.Names)
if m == 0 {
- m = 1 // anonymous field
+ m = 1
}
n += m
}
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index ff04b9e982..08ab218610 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -99,22 +99,23 @@ var pkgDeps = map[string][]string{
// L3 adds reflection and some basic utility packages
// and interface definitions, but nothing that makes
// system calls.
- "crypto": {"L2", "hash"}, // interfaces
- "crypto/cipher": {"L2", "crypto/subtle"},
- "crypto/subtle": {},
- "encoding/base32": {"L2"},
- "encoding/base64": {"L2", "encoding/binary"},
- "encoding/binary": {"L2", "reflect"},
- "hash": {"L2"}, // interfaces
- "hash/adler32": {"L2", "hash"},
- "hash/crc32": {"L2", "hash"},
- "hash/crc64": {"L2", "hash"},
- "hash/fnv": {"L2", "hash"},
- "image": {"L2", "image/color"}, // interfaces
- "image/color": {"L2"}, // interfaces
- "image/color/palette": {"L2", "image/color"},
- "reflect": {"L2"},
- "sort": {"reflect"},
+ "crypto": {"L2", "hash"}, // interfaces
+ "crypto/cipher": {"L2", "crypto/subtle", "crypto/internal/subtle"},
+ "crypto/internal/subtle": {"unsafe", "reflect"}, // reflect behind a appengine tag
+ "crypto/subtle": {},
+ "encoding/base32": {"L2"},
+ "encoding/base64": {"L2", "encoding/binary"},
+ "encoding/binary": {"L2", "reflect"},
+ "hash": {"L2"}, // interfaces
+ "hash/adler32": {"L2", "hash"},
+ "hash/crc32": {"L2", "hash"},
+ "hash/crc64": {"L2", "hash"},
+ "hash/fnv": {"L2", "hash"},
+ "image": {"L2", "image/color"}, // interfaces
+ "image/color": {"L2"}, // interfaces
+ "image/color/palette": {"L2", "image/color"},
+ "reflect": {"L2"},
+ "sort": {"reflect"},
"crypto/internal/boring": {"L2", "C", "crypto", "crypto/cipher", "crypto/internal/boring/sig", "crypto/subtle", "encoding/asn1", "hash", "math/big"},
"crypto/internal/boring/fipstls": {"sync/atomic"},
@@ -127,6 +128,7 @@ var pkgDeps = map[string][]string{
"crypto/cipher",
"crypto/internal/boring",
"crypto/internal/boring/fipstls",
+ "crypto/internal/subtle",
"crypto/subtle",
"encoding/base32",
"encoding/base64",
@@ -146,7 +148,7 @@ var pkgDeps = map[string][]string{
// Operating system access.
"syscall": {"L0", "internal/race", "internal/syscall/windows/sysdll", "syscall/js", "unicode/utf16"},
- "syscall/js": {"unsafe"},
+ "syscall/js": {"L0"},
"internal/syscall/unix": {"L0", "syscall"},
"internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll"},
"internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
@@ -236,49 +238,49 @@ var pkgDeps = map[string][]string{
"go/types": {"L4", "GOPARSER", "container/heap", "go/constant"},
// One of a kind.
- "archive/tar": {"L4", "OS", "syscall", "os/user"},
- "archive/zip": {"L4", "OS", "compress/flate"},
- "container/heap": {"sort"},
- "compress/bzip2": {"L4"},
- "compress/flate": {"L4"},
- "compress/gzip": {"L4", "compress/flate"},
- "compress/lzw": {"L4"},
- "compress/zlib": {"L4", "compress/flate"},
- "context": {"errors", "fmt", "reflect", "sync", "time"},
- "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
- "database/sql/driver": {"L4", "context", "time", "database/sql/internal"},
- "debug/dwarf": {"L4"},
- "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"},
- "debug/gosym": {"L4"},
- "debug/macho": {"L4", "OS", "debug/dwarf"},
- "debug/pe": {"L4", "OS", "debug/dwarf"},
- "debug/plan9obj": {"L4", "OS"},
- "encoding": {"L4"},
- "encoding/ascii85": {"L4"},
- "encoding/asn1": {"L4", "math/big"},
- "encoding/csv": {"L4"},
- "encoding/gob": {"L4", "OS", "encoding"},
- "encoding/hex": {"L4"},
- "encoding/json": {"L4", "encoding"},
- "encoding/pem": {"L4"},
- "encoding/xml": {"L4", "encoding"},
- "flag": {"L4", "OS"},
- "go/build": {"L4", "OS", "GOPARSER"},
- "html": {"L4"},
- "image/draw": {"L4", "image/internal/imageutil"},
- "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
- "image/internal/imageutil": {"L4"},
- "image/jpeg": {"L4", "image/internal/imageutil"},
- "image/png": {"L4", "compress/zlib"},
- "index/suffixarray": {"L4", "regexp"},
- "internal/singleflight": {"sync"},
- "internal/trace": {"L4", "OS"},
- "math/big": {"L4"},
- "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
- "mime/quotedprintable": {"L4"},
- "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"},
- "net/url": {"L4"},
- "plugin": {"L0", "OS", "CGO"},
+ "archive/tar": {"L4", "OS", "syscall", "os/user"},
+ "archive/zip": {"L4", "OS", "compress/flate"},
+ "container/heap": {"sort"},
+ "compress/bzip2": {"L4"},
+ "compress/flate": {"L4"},
+ "compress/gzip": {"L4", "compress/flate"},
+ "compress/lzw": {"L4"},
+ "compress/zlib": {"L4", "compress/flate"},
+ "context": {"errors", "fmt", "reflect", "sync", "time"},
+ "database/sql": {"L4", "container/list", "context", "database/sql/driver", "database/sql/internal"},
+ "database/sql/driver": {"L4", "context", "time", "database/sql/internal"},
+ "debug/dwarf": {"L4"},
+ "debug/elf": {"L4", "OS", "debug/dwarf", "compress/zlib"},
+ "debug/gosym": {"L4"},
+ "debug/macho": {"L4", "OS", "debug/dwarf", "compress/zlib"},
+ "debug/pe": {"L4", "OS", "debug/dwarf", "compress/zlib"},
+ "debug/plan9obj": {"L4", "OS"},
+ "encoding": {"L4"},
+ "encoding/ascii85": {"L4"},
+ "encoding/asn1": {"L4", "math/big"},
+ "encoding/csv": {"L4"},
+ "encoding/gob": {"L4", "OS", "encoding"},
+ "encoding/hex": {"L4"},
+ "encoding/json": {"L4", "encoding"},
+ "encoding/pem": {"L4"},
+ "encoding/xml": {"L4", "encoding"},
+ "flag": {"L4", "OS"},
+ "go/build": {"L4", "OS", "GOPARSER"},
+ "html": {"L4"},
+ "image/draw": {"L4", "image/internal/imageutil"},
+ "image/gif": {"L4", "compress/lzw", "image/color/palette", "image/draw"},
+ "image/internal/imageutil": {"L4"},
+ "image/jpeg": {"L4", "image/internal/imageutil"},
+ "image/png": {"L4", "compress/zlib"},
+ "index/suffixarray": {"L4", "regexp"},
+ "internal/singleflight": {"sync"},
+ "internal/trace": {"L4", "OS"},
+ "math/big": {"L4"},
+ "mime": {"L4", "OS", "syscall", "internal/syscall/windows/registry"},
+ "mime/quotedprintable": {"L4"},
+ "net/internal/socktest": {"L4", "OS", "syscall", "internal/syscall/windows"},
+ "net/url": {"L4"},
+ "plugin": {"L0", "OS", "CGO"},
"runtime/pprof/internal/profile": {"L4", "OS", "compress/gzip", "regexp"},
"testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"},
"text/scanner": {"L4", "OS"},
@@ -423,7 +425,7 @@ var pkgDeps = map[string][]string{
"syscall/js",
},
"net/http/internal": {"L4"},
- "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "reflect", "time"},
+ "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "net/textproto", "reflect", "time"},
// HTTP-using packages.
"expvar": {"L4", "OS", "encoding/json", "net/http"},
diff --git a/src/go/doc/example.go b/src/go/doc/example.go
index a89f29b40f..7fc6dedf7f 100644
--- a/src/go/doc/example.go
+++ b/src/go/doc/example.go
@@ -77,7 +77,7 @@ func Examples(files ...*ast.File) []*Example {
Name: name[len("Example"):],
Doc: doc,
Code: f.Body,
- Play: playExample(file, f.Body),
+ Play: playExample(file, f),
Comments: file.Comments,
Output: output,
Unordered: unordered,
@@ -140,27 +140,39 @@ func isTest(name, prefix string) bool {
// playExample synthesizes a new *ast.File based on the provided
// file with the provided function body as the body of main.
-func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
+func playExample(file *ast.File, f *ast.FuncDecl) *ast.File {
+ body := f.Body
+
if !strings.HasSuffix(file.Name.Name, "_test") {
// We don't support examples that are part of the
// greater package (yet).
return nil
}
- // Find top-level declarations in the file.
- topDecls := make(map[*ast.Object]bool)
+ // Collect top-level declarations in the file.
+ topDecls := make(map[*ast.Object]ast.Decl)
+ typMethods := make(map[string][]ast.Decl)
+
for _, decl := range file.Decls {
switch d := decl.(type) {
case *ast.FuncDecl:
- topDecls[d.Name.Obj] = true
+ if d.Recv == nil {
+ topDecls[d.Name.Obj] = d
+ } else {
+ if len(d.Recv.List) == 1 {
+ t := d.Recv.List[0].Type
+ tname, _ := baseTypeName(t)
+ typMethods[tname] = append(typMethods[tname], d)
+ }
+ }
case *ast.GenDecl:
for _, spec := range d.Specs {
switch s := spec.(type) {
case *ast.TypeSpec:
- topDecls[s.Name.Obj] = true
+ topDecls[s.Name.Obj] = d
case *ast.ValueSpec:
- for _, id := range s.Names {
- topDecls[id.Obj] = true
+ for _, name := range s.Names {
+ topDecls[name.Obj] = d
}
}
}
@@ -169,36 +181,59 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
// Find unresolved identifiers and uses of top-level declarations.
unresolved := make(map[string]bool)
- usesTopDecl := false
+ var depDecls []ast.Decl
+ hasDepDecls := make(map[ast.Decl]bool)
+
var inspectFunc func(ast.Node) bool
inspectFunc = func(n ast.Node) bool {
- // For selector expressions, only inspect the left hand side.
- // (For an expression like fmt.Println, only add "fmt" to the
- // set of unresolved names, not "Println".)
- if e, ok := n.(*ast.SelectorExpr); ok {
+ switch e := n.(type) {
+ case *ast.Ident:
+ if e.Obj == nil {
+ unresolved[e.Name] = true
+ } else if d := topDecls[e.Obj]; d != nil {
+ if !hasDepDecls[d] {
+ hasDepDecls[d] = true
+ depDecls = append(depDecls, d)
+ }
+ }
+ return true
+ case *ast.SelectorExpr:
+ // For selector expressions, only inspect the left hand side.
+ // (For an expression like fmt.Println, only add "fmt" to the
+ // set of unresolved names, not "Println".)
ast.Inspect(e.X, inspectFunc)
return false
- }
- // For key value expressions, only inspect the value
- // as the key should be resolved by the type of the
- // composite literal.
- if e, ok := n.(*ast.KeyValueExpr); ok {
+ case *ast.KeyValueExpr:
+ // For key value expressions, only inspect the value
+ // as the key should be resolved by the type of the
+ // composite literal.
ast.Inspect(e.Value, inspectFunc)
return false
}
- if id, ok := n.(*ast.Ident); ok {
- if id.Obj == nil {
- unresolved[id.Name] = true
- } else if topDecls[id.Obj] {
- usesTopDecl = true
- }
- }
return true
}
ast.Inspect(body, inspectFunc)
- if usesTopDecl {
- // We don't support examples that are not self-contained (yet).
- return nil
+ for i := 0; i < len(depDecls); i++ {
+ switch d := depDecls[i].(type) {
+ case *ast.FuncDecl:
+ ast.Inspect(d.Body, inspectFunc)
+ case *ast.GenDecl:
+ for _, spec := range d.Specs {
+ switch s := spec.(type) {
+ case *ast.TypeSpec:
+ ast.Inspect(s.Type, inspectFunc)
+
+ depDecls = append(depDecls, typMethods[s.Name.Name]...)
+ case *ast.ValueSpec:
+ if s.Type != nil {
+ ast.Inspect(s.Type, inspectFunc)
+ }
+ for _, val := range s.Values {
+ ast.Inspect(val, inspectFunc)
+ }
+ }
+ }
+ }
}
// Remove predeclared identifiers from unresolved list.
@@ -261,6 +296,20 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
// end position.
body, comments = stripOutputComment(body, comments)
+ // Include documentation belonging to dependent declarations.
+ for _, d := range depDecls {
+ switch d := d.(type) {
+ case *ast.GenDecl:
+ if d.Doc != nil {
+ comments = append(comments, d.Doc)
+ }
+ case *ast.FuncDecl:
+ if d.Doc != nil {
+ comments = append(comments, d.Doc)
+ }
+ }
+ }
+
// Synthesize import declaration.
importDecl := &ast.GenDecl{
Tok: token.IMPORT,
@@ -279,14 +328,27 @@ func playExample(file *ast.File, body *ast.BlockStmt) *ast.File {
// Synthesize main function.
funcDecl := &ast.FuncDecl{
Name: ast.NewIdent("main"),
- Type: &ast.FuncType{Params: &ast.FieldList{}}, // FuncType.Params must be non-nil
+ Type: f.Type,
Body: body,
}
+ decls := make([]ast.Decl, 0, 2+len(depDecls))
+ decls = append(decls, importDecl)
+ decls = append(decls, depDecls...)
+ decls = append(decls, funcDecl)
+
+ sort.Slice(decls, func(i, j int) bool {
+ return decls[i].Pos() < decls[j].Pos()
+ })
+
+ sort.Slice(comments, func(i, j int) bool {
+ return comments[i].Pos() < comments[j].Pos()
+ })
+
// Synthesize file.
return &ast.File{
Name: ast.NewIdent("main"),
- Decls: []ast.Decl{importDecl, funcDecl},
+ Decls: decls,
Comments: comments,
}
}
diff --git a/src/go/doc/example_test.go b/src/go/doc/example_test.go
index e154ea8bfc..f0c3000504 100644
--- a/src/go/doc/example_test.go
+++ b/src/go/doc/example_test.go
@@ -21,6 +21,7 @@ import (
"flag"
"fmt"
"log"
+ "sort"
"os/exec"
)
@@ -67,6 +68,46 @@ var keyValueTopDecl = struct {
func ExampleKeyValueTopDecl() {
fmt.Print(keyValueTopDecl)
+ // Output: a: "B", b: 2
+}
+
+// Person represents a person by name and age.
+type Person struct {
+ Name string
+ Age int
+}
+
+// String returns a string representation of the Person.
+func (p Person) String() string {
+ return fmt.Sprintf("%s: %d", p.Name, p.Age)
+}
+
+// ByAge implements sort.Interface for []Person based on
+// the Age field.
+type ByAge []Person
+
+// Len returns the number of elements in ByAge.
+func (a (ByAge)) Len() int { return len(a) }
+
+// Swap swaps the elements in ByAge.
+func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
+
+// people is the array of Person
+var people = []Person{
+ {"Bob", 31},
+ {"John", 42},
+ {"Michael", 17},
+ {"Jenny", 26},
+}
+
+func ExampleSort() {
+ fmt.Println(people)
+ sort.Sort(ByAge(people))
+ fmt.Println(people)
+ // Output:
+ // [Bob: 31 John: 42 Michael: 17 Jenny: 26]
+ // [Michael: 17 Jenny: 26 Bob: 31 John: 42]
}
`
@@ -93,8 +134,14 @@ var exampleTestCases = []struct {
Output: "Name: \"play\"\n",
},
{
- Name: "KeyValueTopDecl",
- Play: "<nil>",
+ Name: "KeyValueTopDecl",
+ Play: exampleKeyValueTopDeclPlay,
+ Output: "a: \"B\", b: 2\n",
+ },
+ {
+ Name: "Sort",
+ Play: exampleSortPlay,
+ Output: "[Bob: 31 John: 42 Michael: 17 Jenny: 26]\n[Michael: 17 Jenny: 26 Bob: 31 John: 42]\n",
},
}
@@ -158,6 +205,69 @@ func main() {
}
`
+const exampleKeyValueTopDeclPlay = `package main
+
+import (
+ "fmt"
+)
+
+var keyValueTopDecl = struct {
+ a string
+ b int
+}{
+ a: "B",
+ b: 2,
+}
+
+func main() {
+ fmt.Print(keyValueTopDecl)
+}
+`
+
+const exampleSortPlay = `package main
+
+import (
+ "fmt"
+ "sort"
+)
+
+// Person represents a person by name and age.
+type Person struct {
+ Name string
+ Age int
+}
+
+// String returns a string representation of the Person.
+func (p Person) String() string {
+ return fmt.Sprintf("%s: %d", p.Name, p.Age)
+}
+
+// ByAge implements sort.Interface for []Person based on
+// the Age field.
+type ByAge []Person
+
+// Len returns the number of elements in ByAge.
+func (a ByAge) Len() int { return len(a) }
+
+// Swap swaps the elements in ByAge.
+func (a ByAge) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
+func (a ByAge) Less(i, j int) bool { return a[i].Age < a[j].Age }
+
+// people is the array of Person
+var people = []Person{
+ {"Bob", 31},
+ {"John", 42},
+ {"Michael", 17},
+ {"Jenny", 26},
+}
+
+func main() {
+ fmt.Println(people)
+ sort.Sort(ByAge(people))
+ fmt.Println(people)
+}
+`
+
func TestExamples(t *testing.T) {
fset := token.NewFileSet()
file, err := parser.ParseFile(fset, "test.go", strings.NewReader(exampleTestFile), parser.ParseComments)
diff --git a/src/go/doc/reader.go b/src/go/doc/reader.go
index 5d6f6e8fb0..21c02920ab 100644
--- a/src/go/doc/reader.go
+++ b/src/go/doc/reader.go
@@ -104,6 +104,8 @@ func baseTypeName(x ast.Expr) (name string, imported bool) {
// assume type is imported
return t.Sel.Name, true
}
+ case *ast.ParenExpr:
+ return baseTypeName(t.X)
case *ast.StarExpr:
return baseTypeName(t.X)
}
@@ -399,9 +401,9 @@ func (r *reader) readFunc(fun *ast.FuncDecl) {
// with the first type in result signature (there may
// be more than one result)
factoryType := res.Type
- if t, ok := factoryType.(*ast.ArrayType); ok && t.Len == nil {
- // We consider functions that return slices of type T (or
- // pointers to T) as factory functions of T.
+ if t, ok := factoryType.(*ast.ArrayType); ok {
+ // We consider functions that return slices or arrays of type
+ // T (or pointers to T) as factory functions of T.
factoryType = t.Elt
}
if n, imp := baseTypeName(factoryType); !imp && r.isVisible(n) {
diff --git a/src/go/doc/testdata/issue18063.0.golden b/src/go/doc/testdata/issue22856.0.golden
index 0afbc169c2..a88f43f4bd 100644
--- a/src/go/doc/testdata/issue18063.0.golden
+++ b/src/go/doc/testdata/issue22856.0.golden
@@ -1,19 +1,13 @@
//
-PACKAGE issue18063
+PACKAGE issue22856
IMPORTPATH
- testdata/issue18063
+ testdata/issue22856
FILENAMES
- testdata/issue18063.go
+ testdata/issue22856.go
FUNCTIONS
- // NewArray is not a factory function because arrays of type T are ...
- func NewArray() [1]T
-
- // NewPointerArray is not a factory function because arrays of ...
- func NewPointerArray() [1]*T
-
// NewPointerSliceOfSlice is not a factory function because slices ...
func NewPointerSliceOfSlice() [][]*T
@@ -32,9 +26,15 @@ TYPES
func New() T
//
+ func NewArray() [1]T
+
+ //
func NewPointer() *T
//
+ func NewPointerArray() [1]*T
+
+ //
func NewPointerOfPointer() **T
//
diff --git a/src/go/doc/testdata/issue18063.1.golden b/src/go/doc/testdata/issue22856.1.golden
index 0afbc169c2..a88f43f4bd 100644
--- a/src/go/doc/testdata/issue18063.1.golden
+++ b/src/go/doc/testdata/issue22856.1.golden
@@ -1,19 +1,13 @@
//
-PACKAGE issue18063
+PACKAGE issue22856
IMPORTPATH
- testdata/issue18063
+ testdata/issue22856
FILENAMES
- testdata/issue18063.go
+ testdata/issue22856.go
FUNCTIONS
- // NewArray is not a factory function because arrays of type T are ...
- func NewArray() [1]T
-
- // NewPointerArray is not a factory function because arrays of ...
- func NewPointerArray() [1]*T
-
// NewPointerSliceOfSlice is not a factory function because slices ...
func NewPointerSliceOfSlice() [][]*T
@@ -32,9 +26,15 @@ TYPES
func New() T
//
+ func NewArray() [1]T
+
+ //
func NewPointer() *T
//
+ func NewPointerArray() [1]*T
+
+ //
func NewPointerOfPointer() **T
//
diff --git a/src/go/doc/testdata/issue18063.2.golden b/src/go/doc/testdata/issue22856.2.golden
index 0afbc169c2..a88f43f4bd 100644
--- a/src/go/doc/testdata/issue18063.2.golden
+++ b/src/go/doc/testdata/issue22856.2.golden
@@ -1,19 +1,13 @@
//
-PACKAGE issue18063
+PACKAGE issue22856
IMPORTPATH
- testdata/issue18063
+ testdata/issue22856
FILENAMES
- testdata/issue18063.go
+ testdata/issue22856.go
FUNCTIONS
- // NewArray is not a factory function because arrays of type T are ...
- func NewArray() [1]T
-
- // NewPointerArray is not a factory function because arrays of ...
- func NewPointerArray() [1]*T
-
// NewPointerSliceOfSlice is not a factory function because slices ...
func NewPointerSliceOfSlice() [][]*T
@@ -32,9 +26,15 @@ TYPES
func New() T
//
+ func NewArray() [1]T
+
+ //
func NewPointer() *T
//
+ func NewPointerArray() [1]*T
+
+ //
func NewPointerOfPointer() **T
//
diff --git a/src/go/doc/testdata/issue18063.go b/src/go/doc/testdata/issue22856.go
index 1193af51e7..f4569981aa 100644
--- a/src/go/doc/testdata/issue18063.go
+++ b/src/go/doc/testdata/issue22856.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-package issue18063
+package issue22856
type T struct{}
@@ -11,14 +11,8 @@ func NewPointer() *T { return &T{} }
func NewPointerSlice() []*T { return []*T{&T{}} }
func NewSlice() []T { return []T{T{}} }
func NewPointerOfPointer() **T { x := &T{}; return &x }
-
-// NewArray is not a factory function because arrays of type T are not
-// factory functions of type T.
-func NewArray() [1]T { return [1]T{T{}} }
-
-// NewPointerArray is not a factory function because arrays of type *T are not
-// factory functions of type T.
-func NewPointerArray() [1]*T { return [1]*T{&T{}} }
+func NewArray() [1]T { return [1]T{T{}} }
+func NewPointerArray() [1]*T { return [1]*T{&T{}} }
// NewSliceOfSlice is not a factory function because slices of a slice of
// type *T are not factory functions of type T.
diff --git a/src/go/internal/gccgoimporter/ar.go b/src/go/internal/gccgoimporter/ar.go
new file mode 100644
index 0000000000..ebd08b8f35
--- /dev/null
+++ b/src/go/internal/gccgoimporter/ar.go
@@ -0,0 +1,148 @@
+// Copyright 2018 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 gccgoimporter
+
+import (
+ "bytes"
+ "debug/elf"
+ "errors"
+ "fmt"
+ "io"
+ "strconv"
+ "strings"
+)
+
+// Magic strings for different archive file formats.
+const (
+ armag = "!<arch>\n"
+ armagt = "!<thin>\n"
+ armagb = "<bigaf>\n"
+)
+
+// Offsets and sizes for fields in a standard archive header.
+const (
+ arNameOff = 0
+ arNameSize = 16
+ arDateOff = arNameOff + arNameSize
+ arDateSize = 12
+ arUIDOff = arDateOff + arDateSize
+ arUIDSize = 6
+ arGIDOff = arUIDOff + arUIDSize
+ arGIDSize = 6
+ arModeOff = arGIDOff + arGIDSize
+ arModeSize = 8
+ arSizeOff = arModeOff + arModeSize
+ arSizeSize = 10
+ arFmagOff = arSizeOff + arSizeSize
+ arFmagSize = 2
+
+ arHdrSize = arFmagOff + arFmagSize
+)
+
+// The contents of the fmag field of a standard archive header.
+const arfmag = "`\n"
+
+// arExportData takes an archive file and returns a ReadSeeker for the
+// export data in that file. This assumes that there is only one
+// object in the archive containing export data, which is not quite
+// what gccgo does; gccgo concatenates together all the export data
+// for all the objects in the file. In practice that case does not arise.
+func arExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
+ if _, err := archive.Seek(0, io.SeekStart); err != nil {
+ return nil, err
+ }
+
+ var buf [len(armag)]byte
+ if _, err := archive.Read(buf[:]); err != nil {
+ return nil, err
+ }
+
+ switch string(buf[:]) {
+ case armag:
+ return standardArExportData(archive)
+ case armagt:
+ return nil, errors.New("unsupported thin archive")
+ case armagb:
+ return nil, errors.New("unsupported AIX big archive")
+ default:
+ return nil, fmt.Errorf("unrecognized archive file format %q", buf[:])
+ }
+}
+
+// standardArExportData returns export data form a standard archive.
+func standardArExportData(archive io.ReadSeeker) (io.ReadSeeker, error) {
+ off := int64(len(armag))
+ for {
+ var hdrBuf [arHdrSize]byte
+ if _, err := archive.Read(hdrBuf[:]); err != nil {
+ return nil, err
+ }
+ off += arHdrSize
+
+ if bytes.Compare(hdrBuf[arFmagOff:arFmagOff+arFmagSize], []byte(arfmag)) != 0 {
+ return nil, fmt.Errorf("archive header format header (%q)", hdrBuf[:])
+ }
+
+ size, err := strconv.ParseInt(strings.TrimSpace(string(hdrBuf[arSizeOff:arSizeOff+arSizeSize])), 10, 64)
+ if err != nil {
+ return nil, fmt.Errorf("error parsing size in archive header (%q): %v", hdrBuf[:], err)
+ }
+
+ fn := hdrBuf[arNameOff : arNameOff+arNameSize]
+ if fn[0] == '/' && (fn[1] == ' ' || fn[1] == '/' || bytes.Compare(fn[:8], []byte("/SYM64/ ")) == 0) {
+ // Archive symbol table or extended name table,
+ // which we don't care about.
+ } else {
+ archiveAt := readerAtFromSeeker(archive)
+ ret, err := elfFromAr(io.NewSectionReader(archiveAt, off, size))
+ if ret != nil || err != nil {
+ return ret, err
+ }
+ }
+
+ if size&1 != 0 {
+ size++
+ }
+ off += size
+ if _, err := archive.Seek(off, io.SeekStart); err != nil {
+ return nil, err
+ }
+ }
+}
+
+// elfFromAr tries to get export data from an archive member as an ELF file.
+// If there is no export data, this returns nil, nil.
+func elfFromAr(member *io.SectionReader) (io.ReadSeeker, error) {
+ ef, err := elf.NewFile(member)
+ if err != nil {
+ return nil, err
+ }
+ sec := ef.Section(".go_export")
+ if sec == nil {
+ return nil, nil
+ }
+ return sec.Open(), nil
+}
+
+// readerAtFromSeeker turns an io.ReadSeeker into an io.ReaderAt.
+// This is only safe because there won't be any concurrent seeks
+// while this code is executing.
+func readerAtFromSeeker(rs io.ReadSeeker) io.ReaderAt {
+ if ret, ok := rs.(io.ReaderAt); ok {
+ return ret
+ }
+ return seekerReadAt{rs}
+}
+
+type seekerReadAt struct {
+ seeker io.ReadSeeker
+}
+
+func (sra seekerReadAt) ReadAt(p []byte, off int64) (int, error) {
+ if _, err := sra.seeker.Seek(off, io.SeekStart); err != nil {
+ return 0, err
+ }
+ return sra.seeker.Read(p)
+}
diff --git a/src/go/internal/gccgoimporter/importer.go b/src/go/internal/gccgoimporter/importer.go
index d4998cf2a2..159cc50719 100644
--- a/src/go/internal/gccgoimporter/importer.go
+++ b/src/go/internal/gccgoimporter/importer.go
@@ -6,13 +6,11 @@
package gccgoimporter // import "go/internal/gccgoimporter"
import (
- "bytes"
"debug/elf"
"fmt"
"go/types"
"io"
"os"
- "os/exec"
"path/filepath"
"strings"
)
@@ -98,18 +96,8 @@ func openExportFile(fpath string) (reader io.ReadSeeker, closer io.Closer, err e
return
case archiveMagic:
- // TODO(pcc): Read the archive directly instead of using "ar".
- f.Close()
- closer = nil
-
- cmd := exec.Command("ar", "p", fpath)
- var out []byte
- out, err = cmd.Output()
- if err != nil {
- return
- }
-
- elfreader = bytes.NewReader(out)
+ reader, err = arExportData(f)
+ return
default:
elfreader = f
@@ -189,17 +177,24 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo
reader = r
}
- var magic [4]byte
- _, err = reader.Read(magic[:])
+ var magics string
+ magics, err = readMagic(reader)
if err != nil {
return
}
- _, err = reader.Seek(0, io.SeekStart)
- if err != nil {
- return
+
+ if magics == archiveMagic {
+ reader, err = arExportData(reader)
+ if err != nil {
+ return
+ }
+ magics, err = readMagic(reader)
+ if err != nil {
+ return
+ }
}
- switch string(magic[:]) {
+ switch magics {
case gccgov1Magic, gccgov2Magic:
var p parser
p.init(fpath, reader, imports)
@@ -230,9 +225,22 @@ func GetImporter(searchpaths []string, initmap map[*types.Package]InitData) Impo
// }
default:
- err = fmt.Errorf("unrecognized magic string: %q", string(magic[:]))
+ err = fmt.Errorf("unrecognized magic string: %q", magics)
}
return
}
}
+
+// readMagic reads the four bytes at the start of a ReadSeeker and
+// returns them as a string.
+func readMagic(reader io.ReadSeeker) (string, error) {
+ var magic [4]byte
+ if _, err := reader.Read(magic[:]); err != nil {
+ return "", err
+ }
+ if _, err := reader.Seek(0, io.SeekStart); err != nil {
+ return "", err
+ }
+ return string(magic[:]), nil
+}
diff --git a/src/go/internal/gccgoimporter/importer_test.go b/src/go/internal/gccgoimporter/importer_test.go
index 01ab47a445..5a699687bd 100644
--- a/src/go/internal/gccgoimporter/importer_test.go
+++ b/src/go/internal/gccgoimporter/importer_test.go
@@ -101,6 +101,7 @@ var importerTests = [...]importerTest{
{pkgpath: "unicode", name: "IsUpper", want: "func IsUpper(r rune) bool"},
{pkgpath: "unicode", name: "MaxRune", want: "const MaxRune untyped rune", wantval: "1114111"},
{pkgpath: "imports", wantinits: []string{"imports..import", "fmt..import", "math..import"}},
+ {pkgpath: "importsar", name: "Hello", want: "var Hello string"},
{pkgpath: "alias", name: "IntAlias2", want: "type IntAlias2 = Int"},
{pkgpath: "escapeinfo", name: "NewT", want: "func NewT(data []byte) *T"},
}
diff --git a/src/go/internal/gccgoimporter/parser.go b/src/go/internal/gccgoimporter/parser.go
index 7b4cc06760..9f8c19b638 100644
--- a/src/go/internal/gccgoimporter/parser.go
+++ b/src/go/internal/gccgoimporter/parser.go
@@ -600,7 +600,7 @@ func (p *parser) parseInterfaceType(pkg *types.Package) types.Type {
}
p.expect('}')
- return types.NewInterface2(methods, embeddeds)
+ return types.NewInterfaceType(methods, embeddeds)
}
// PointerType = "*" ("any" | Type) .
@@ -906,10 +906,3 @@ func (p *parser) parsePackage() *types.Package {
p.pkg.MarkComplete()
return p.pkg
}
-
-// InitData = { InitDataDirective } .
-func (p *parser) parseInitData() {
- for p.tok != scanner.EOF {
- p.parseInitDataDirective()
- }
-}
diff --git a/src/go/internal/gccgoimporter/testdata/libimportsar.a b/src/go/internal/gccgoimporter/testdata/libimportsar.a
new file mode 100644
index 0000000000..6f30758151
--- /dev/null
+++ b/src/go/internal/gccgoimporter/testdata/libimportsar.a
Binary files differ
diff --git a/src/go/internal/gcimporter/bimport.go b/src/go/internal/gcimporter/bimport.go
index 73ce465eab..4e3023b906 100644
--- a/src/go/internal/gcimporter/bimport.go
+++ b/src/go/internal/gcimporter/bimport.go
@@ -50,24 +50,24 @@ type importer struct {
// compromised, an error is returned.
func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
// catch panics and return them as errors
+ const currentVersion = 6
+ version := -1 // unknown version
defer func() {
if e := recover(); e != nil {
- // The package (filename) causing the problem is added to this
- // error by a wrapper in the caller (Import in gcimporter.go).
// Return a (possibly nil or incomplete) package unchanged (see #16088).
- err = fmt.Errorf("cannot import, possibly version skew (%v) - reinstall package", e)
+ if version > currentVersion {
+ err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
+ } else {
+ err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
+ }
}
}()
- if len(data) > 0 && data[0] == 'i' {
- return iImportData(fset, imports, data[1:], path)
- }
-
p := importer{
imports: imports,
data: data,
importpath: path,
- version: -1, // unknown version
+ version: version,
strList: []string{""}, // empty string is mapped to 0
pathList: []string{""}, // empty string is mapped to 0
fake: fakeFileSet{
@@ -92,7 +92,7 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
p.posInfoFormat = p.int() != 0
versionstr = p.string()
if versionstr == "v1" {
- p.version = 0
+ version = 0
}
} else {
// Go1.8 extensible encoding
@@ -100,24 +100,25 @@ func BImportData(fset *token.FileSet, imports map[string]*types.Package, data []
versionstr = p.rawStringln(b)
if s := strings.SplitN(versionstr, " ", 3); len(s) >= 2 && s[0] == "version" {
if v, err := strconv.Atoi(s[1]); err == nil && v > 0 {
- p.version = v
+ version = v
}
}
}
+ p.version = version
// read version specific flags - extend as necessary
switch p.version {
- // case 7:
+ // case currentVersion:
// ...
// fallthrough
- case 6, 5, 4, 3, 2, 1:
+ case currentVersion, 5, 4, 3, 2, 1:
p.debugFormat = p.rawStringln(p.rawByte()) == "debug"
p.trackAllTypes = p.int() != 0
p.posInfoFormat = p.int() != 0
case 0:
// Go1.7 encoding format - nothing to do here
default:
- errorf("unknown export format version %d (%q)", p.version, versionstr)
+ errorf("unknown bexport format version %d (%q)", p.version, versionstr)
}
// --- generic export data ---
@@ -535,7 +536,7 @@ func (p *importer) typ(parent *types.Package, tname *types.Named) types.Type {
embeddeds = append(embeddeds, p.typ(parent, nil))
}
- t := types.NewInterface2(p.methodList(parent, tname), embeddeds)
+ t := types.NewInterfaceType(p.methodList(parent, tname), embeddeds)
p.interfaceList = append(p.interfaceList, t)
if p.trackAllTypes {
p.typList[n] = t
diff --git a/src/go/internal/gcimporter/gcimporter.go b/src/go/internal/gcimporter/gcimporter.go
index cf89fcd1b4..d117f6fe4d 100644
--- a/src/go/internal/gcimporter/gcimporter.go
+++ b/src/go/internal/gcimporter/gcimporter.go
@@ -144,16 +144,27 @@ func Import(packages map[string]*types.Package, path, srcDir string, lookup func
switch hdr {
case "$$\n":
err = fmt.Errorf("import %q: old export format no longer supported (recompile library)", path)
+
case "$$B\n":
var data []byte
data, err = ioutil.ReadAll(buf)
- if err == nil {
- // TODO(gri): allow clients of go/importer to provide a FileSet.
- // Or, define a new standard go/types/gcexportdata package.
- fset := token.NewFileSet()
+ if err != nil {
+ break
+ }
+
+ // TODO(gri): allow clients of go/importer to provide a FileSet.
+ // Or, define a new standard go/types/gcexportdata package.
+ fset := token.NewFileSet()
+
+ // The indexed export format starts with an 'i'; the older
+ // binary export format starts with a 'c', 'd', or 'v'
+ // (from "version"). Select appropriate importer.
+ if len(data) > 0 && data[0] == 'i' {
+ _, pkg, err = iImportData(fset, packages, data[1:], id)
+ } else {
_, pkg, err = BImportData(fset, packages, data, id)
- return
}
+
default:
err = fmt.Errorf("unknown export data header: %q", hdr)
}
diff --git a/src/go/internal/gcimporter/gcimporter_test.go b/src/go/internal/gcimporter/gcimporter_test.go
index 308f93e8bd..d496f2e57d 100644
--- a/src/go/internal/gcimporter/gcimporter_test.go
+++ b/src/go/internal/gcimporter/gcimporter_test.go
@@ -141,9 +141,21 @@ func TestVersionHandling(t *testing.T) {
}
pkgpath := "./" + name[:len(name)-2]
+ if testing.Verbose() {
+ t.Logf("importing %s", name)
+ }
+
// test that export data can be imported
_, err := Import(make(map[string]*types.Package), pkgpath, dir, nil)
if err != nil {
+ // ok to fail if it fails with a newer version error for select files
+ if strings.Contains(err.Error(), "newer version") {
+ switch name {
+ case "test_go1.11_999b.a", "test_go1.11_999i.a":
+ continue
+ }
+ // fall through
+ }
t.Errorf("import %q failed: %v", pkgpath, err)
continue
}
diff --git a/src/go/internal/gcimporter/iimport.go b/src/go/internal/gcimporter/iimport.go
index 1d13449ef6..bf480641df 100644
--- a/src/go/internal/gcimporter/iimport.go
+++ b/src/go/internal/gcimporter/iimport.go
@@ -10,6 +10,7 @@ package gcimporter
import (
"bytes"
"encoding/binary"
+ "fmt"
"go/constant"
"go/token"
"go/types"
@@ -60,13 +61,25 @@ const (
// If the export data version is not recognized or the format is otherwise
// compromised, an error is returned.
func iImportData(fset *token.FileSet, imports map[string]*types.Package, data []byte, path string) (_ int, pkg *types.Package, err error) {
+ const currentVersion = 0
+ version := -1
+ defer func() {
+ if e := recover(); e != nil {
+ if version > currentVersion {
+ err = fmt.Errorf("cannot import %q (%v), export data is newer version - update tool", path, e)
+ } else {
+ err = fmt.Errorf("cannot import %q (%v), possibly version skew - reinstall package", path, e)
+ }
+ }
+ }()
+
r := &intReader{bytes.NewReader(data), path}
- version := r.uint64()
+ version = int(r.uint64())
switch version {
- case 0:
+ case currentVersion:
default:
- errorf("cannot import %q: unknown iexport format version %d", path, version)
+ errorf("unknown iexport format version %d", version)
}
sLen := int64(r.uint64())
@@ -522,7 +535,7 @@ func (r *importReader) doType(base *types.Named) types.Type {
methods[i] = types.NewFunc(mpos, r.currPkg, mname, msig)
}
- typ := types.NewInterface2(methods, embeddeds)
+ typ := types.NewInterfaceType(methods, embeddeds)
r.p.interfaceList = append(r.p.interfaceList, typ)
return typ
}
diff --git a/src/go/internal/gcimporter/testdata/versions/test.go b/src/go/internal/gcimporter/testdata/versions/test.go
index ac9c968c2d..227fc09251 100644
--- a/src/go/internal/gcimporter/testdata/versions/test.go
+++ b/src/go/internal/gcimporter/testdata/versions/test.go
@@ -11,7 +11,10 @@
//
// go build -o test_go1.$X_$Y.a test.go
//
-// with $X = Go version and $Y = export format version.
+// with $X = Go version and $Y = export format version
+// (add 'b' or 'i' to distinguish between binary and
+// indexed format starting with 1.11 as long as both
+// formats are supported).
//
// Make sure this source is extended such that it exercises
// whatever export format change has taken place.
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a
new file mode 100644
index 0000000000..b00fefed04
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/versions/test_go1.11_0i.a
Binary files differ
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a
new file mode 100644
index 0000000000..c0a211e917
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/versions/test_go1.11_6b.a
Binary files differ
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a
new file mode 100644
index 0000000000..c35d22dce6
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999b.a
Binary files differ
diff --git a/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a
new file mode 100644
index 0000000000..99401d7c37
--- /dev/null
+++ b/src/go/internal/gcimporter/testdata/versions/test_go1.11_999i.a
Binary files differ
diff --git a/src/go/types/sizes.go b/src/go/types/sizes.go
index fda0c95469..7b5410167f 100644
--- a/src/go/types/sizes.go
+++ b/src/go/types/sizes.go
@@ -167,6 +167,7 @@ var gcArchSizes = map[string]*StdSizes{
"mips64le": {8, 8},
"ppc64": {8, 8},
"ppc64le": {8, 8},
+ "riscv64": {8, 8},
"s390x": {8, 8},
"wasm": {8, 8},
// When adding more architectures here,
@@ -178,7 +179,7 @@ var gcArchSizes = map[string]*StdSizes{
//
// Supported architectures for compiler "gc":
// "386", "arm", "arm64", "amd64", "amd64p32", "mips", "mipsle",
-// "mips64", "mips64le", "ppc64", "ppc64le", "s390x", "wasm".
+// "mips64", "mips64le", "ppc64", "ppc64le", "riscv64", "s390x", "wasm".
func SizesFor(compiler, arch string) Sizes {
if compiler != "gc" {
return nil
diff --git a/src/go/types/type.go b/src/go/types/type.go
index 60e3efaec3..d9399a6587 100644
--- a/src/go/types/type.go
+++ b/src/go/types/type.go
@@ -260,7 +260,7 @@ var markComplete = make([]*Func, 0)
// NewInterface takes ownership of the provided methods and may modify their types by setting
// missing receivers. To compute the method set of the interface, Complete must be called.
//
-// Deprecated: Use NewInterface2 instead which allows any (even non-defined) interface types
+// Deprecated: Use NewInterfaceType instead which allows any (even non-defined) interface types
// to be embedded. This is necessary for interfaces that embed alias type names referring to
// non-defined (literal) interface types.
func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
@@ -268,16 +268,16 @@ func NewInterface(methods []*Func, embeddeds []*Named) *Interface {
for i, t := range embeddeds {
tnames[i] = t
}
- return NewInterface2(methods, tnames)
+ return NewInterfaceType(methods, tnames)
}
-// NewInterface2 returns a new (incomplete) interface for the given methods and embedded types.
+// NewInterfaceType returns a new (incomplete) interface for the given methods and embedded types.
// Each embedded type must have an underlying type of interface type (this property is not
// verified for defined types, which may be in the process of being set up and which don't
// have a valid underlying type yet).
-// NewInterface2 takes ownership of the provided methods and may modify their types by setting
+// NewInterfaceType takes ownership of the provided methods and may modify their types by setting
// missing receivers. To compute the method set of the interface, Complete must be called.
-func NewInterface2(methods []*Func, embeddeds []Type) *Interface {
+func NewInterfaceType(methods []*Func, embeddeds []Type) *Interface {
typ := new(Interface)
if len(methods) == 0 && len(embeddeds) == 0 {
@@ -344,9 +344,9 @@ func (t *Interface) Method(i int) *Func { return t.allMethods[i] }
func (t *Interface) Empty() bool { return len(t.allMethods) == 0 }
// Complete computes the interface's method set. It must be called by users of
-// NewInterface after the interface's embedded types are fully defined and
-// before using the interface type in any way other than to form other types.
-// Complete returns the receiver.
+// NewInterfaceType and NewInterface after the interface's embedded types are
+// fully defined and before using the interface type in any way other than to
+// form other types. Complete returns the receiver.
func (t *Interface) Complete() *Interface {
if t.allMethods != nil {
return t
diff --git a/src/go/types/typestring_test.go b/src/go/types/typestring_test.go
index 6ed2d75dfe..0efb7f0013 100644
--- a/src/go/types/typestring_test.go
+++ b/src/go/types/typestring_test.go
@@ -162,19 +162,19 @@ func TestIncompleteInterfaces(t *testing.T) {
{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}), "interface{T /* incomplete */}"},
{NewInterface(nil, []*Named{newDefined(NewInterface([]*Func{m}, nil).Complete())}).Complete(), "interface{T}"},
- {NewInterface2(nil, nil), "interface{/* incomplete */}"},
- {NewInterface2(nil, nil).Complete(), "interface{}"},
- {NewInterface2([]*Func{}, nil), "interface{/* incomplete */}"},
- {NewInterface2([]*Func{}, nil).Complete(), "interface{}"},
- {NewInterface2(nil, []Type{}), "interface{/* incomplete */}"},
- {NewInterface2(nil, []Type{}).Complete(), "interface{}"},
- {NewInterface2([]*Func{m}, nil), "interface{m() /* incomplete */}"},
- {NewInterface2([]*Func{m}, nil).Complete(), "interface{m()}"},
- {NewInterface2(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
- {NewInterface2(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
- {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
- {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
- {NewInterface2(nil, []Type{NewInterface2([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
+ {NewInterfaceType(nil, nil), "interface{/* incomplete */}"},
+ {NewInterfaceType(nil, nil).Complete(), "interface{}"},
+ {NewInterfaceType([]*Func{}, nil), "interface{/* incomplete */}"},
+ {NewInterfaceType([]*Func{}, nil).Complete(), "interface{}"},
+ {NewInterfaceType(nil, []Type{}), "interface{/* incomplete */}"},
+ {NewInterfaceType(nil, []Type{}).Complete(), "interface{}"},
+ {NewInterfaceType([]*Func{m}, nil), "interface{m() /* incomplete */}"},
+ {NewInterfaceType([]*Func{m}, nil).Complete(), "interface{m()}"},
+ {NewInterfaceType(nil, []Type{new(Interface).Complete()}), "interface{interface{} /* incomplete */}"},
+ {NewInterfaceType(nil, []Type{new(Interface).Complete()}).Complete(), "interface{interface{}}"},
+ {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil)}), "interface{interface{m() /* incomplete */} /* incomplete */}"},
+ {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}), "interface{interface{m()} /* incomplete */}"},
+ {NewInterfaceType(nil, []Type{NewInterfaceType([]*Func{m}, nil).Complete()}).Complete(), "interface{interface{m()}}"},
} {
got := test.typ.String()
if got != test.want {
diff --git a/src/go/types/universe.go b/src/go/types/universe.go
index 2ae8a31970..7af6dab320 100644
--- a/src/go/types/universe.go
+++ b/src/go/types/universe.go
@@ -80,7 +80,7 @@ func defPredeclaredTypes() {
res := NewVar(token.NoPos, nil, "", Typ[String])
sig := &Signature{results: NewTuple(res)}
err := NewFunc(token.NoPos, nil, "Error", sig)
- typ := &Named{underlying: NewInterface2([]*Func{err}, nil).Complete()}
+ typ := &Named{underlying: NewInterfaceType([]*Func{err}, nil).Complete()}
sig.recv = NewVar(token.NoPos, nil, "", typ)
def(NewTypeName(token.NoPos, nil, "error", typ))
}
diff --git a/src/html/template/escape.go b/src/html/template/escape.go
index 8517620d3c..f12dafa870 100644
--- a/src/html/template/escape.go
+++ b/src/html/template/escape.go
@@ -142,7 +142,7 @@ func (e *escaper) escape(c context, n parse.Node) context {
// escapeAction escapes an action template node.
func (e *escaper) escapeAction(c context, n *parse.ActionNode) context {
- if len(n.Pipe.Vars) != 0 {
+ if len(n.Pipe.Decl) != 0 {
// A local variable assignment, not an interpolation.
return c
}
diff --git a/src/internal/bytealg/compare_wasm.s b/src/internal/bytealg/compare_wasm.s
index 39bc0fc37a..b412649e04 100644
--- a/src/internal/bytealg/compare_wasm.s
+++ b/src/internal/bytealg/compare_wasm.s
@@ -7,30 +7,30 @@
TEXT ·Compare(SB), NOSPLIT, $0-56
Get SP
- I64Load s1_base+0(FP)
- I64Load s1_len+8(FP)
- I64Load s2_base+24(FP)
- I64Load s2_len+32(FP)
+ I64Load a_base+0(FP)
+ I64Load a_len+8(FP)
+ I64Load b_base+24(FP)
+ I64Load b_len+32(FP)
Call cmpbody<>(SB)
I64Store ret+48(FP)
RET
TEXT bytes·Compare(SB), NOSPLIT, $0-56
Get SP
- I64Load s1_base+0(FP)
- I64Load s1_len+8(FP)
- I64Load s2_base+24(FP)
- I64Load s2_len+32(FP)
+ I64Load a_base+0(FP)
+ I64Load a_len+8(FP)
+ I64Load b_base+24(FP)
+ I64Load b_len+32(FP)
Call cmpbody<>(SB)
I64Store ret+48(FP)
RET
TEXT runtime·cmpstring(SB), NOSPLIT, $0-40
Get SP
- I64Load s1_base+0(FP)
- I64Load s1_len+8(FP)
- I64Load s2_base+16(FP)
- I64Load s2_len+24(FP)
+ I64Load a_base+0(FP)
+ I64Load a_len+8(FP)
+ I64Load b_base+16(FP)
+ I64Load b_len+24(FP)
Call cmpbody<>(SB)
I64Store ret+32(FP)
RET
diff --git a/src/internal/bytealg/indexbyte_wasm.s b/src/internal/bytealg/indexbyte_wasm.s
index 113c7a0a6f..f9f8e65002 100644
--- a/src/internal/bytealg/indexbyte_wasm.s
+++ b/src/internal/bytealg/indexbyte_wasm.s
@@ -6,10 +6,10 @@
#include "textflag.h"
TEXT ·IndexByte(SB), NOSPLIT, $0-40
- I64Load s+0(FP)
+ I64Load b_base+0(FP)
I32WrapI64
I32Load8U c+24(FP)
- I64Load s_len+8(FP)
+ I64Load b_len+8(FP)
I32WrapI64
Call memchr<>(SB)
I64ExtendSI32
@@ -18,7 +18,7 @@ TEXT ·IndexByte(SB), NOSPLIT, $0-40
Get SP
I64Const $-1
Get R0
- I64Load s+0(FP)
+ I64Load b_base+0(FP)
I64Sub
Get R0
I64Eqz $0
@@ -29,7 +29,7 @@ TEXT ·IndexByte(SB), NOSPLIT, $0-40
TEXT ·IndexByteString(SB), NOSPLIT, $0-32
Get SP
- I64Load s+0(FP)
+ I64Load s_base+0(FP)
I32WrapI64
I32Load8U c+16(FP)
I64Load s_len+8(FP)
@@ -40,7 +40,7 @@ TEXT ·IndexByteString(SB), NOSPLIT, $0-32
I64Const $-1
Get R0
- I64Load s+0(FP)
+ I64Load s_base+0(FP)
I64Sub
Get R0
I64Eqz $0
@@ -51,10 +51,10 @@ TEXT ·IndexByteString(SB), NOSPLIT, $0-32
TEXT bytes·IndexByte(SB), NOSPLIT, $0-40
Get SP
- I64Load s+0(FP)
+ I64Load b_base+0(FP)
I32WrapI64
I32Load8U c+24(FP)
- I64Load s_len+8(FP)
+ I64Load b_len+8(FP)
I32WrapI64
Call memchr<>(SB)
I64ExtendSI32
@@ -62,7 +62,7 @@ TEXT bytes·IndexByte(SB), NOSPLIT, $0-40
I64Const $-1
Get R0
- I64Load s+0(FP)
+ I64Load b_base+0(FP)
I64Sub
Get R0
I64Eqz $0
@@ -73,7 +73,7 @@ TEXT bytes·IndexByte(SB), NOSPLIT, $0-40
TEXT strings·IndexByte(SB), NOSPLIT, $0-32
Get SP
- I64Load s+0(FP)
+ I64Load s_base+0(FP)
I32WrapI64
I32Load8U c+16(FP)
I64Load s_len+8(FP)
@@ -84,7 +84,7 @@ TEXT strings·IndexByte(SB), NOSPLIT, $0-32
I64Const $-1
Get R0
- I64Load s+0(FP)
+ I64Load s_base+0(FP)
I64Sub
Get R0
I64Eqz $0
diff --git a/src/internal/cpu/cpu.go b/src/internal/cpu/cpu.go
index b1a8d9bf63..2569024245 100644
--- a/src/internal/cpu/cpu.go
+++ b/src/internal/cpu/cpu.go
@@ -98,14 +98,24 @@ type arm64 struct {
var S390X s390x
type s390x struct {
- _ [CacheLineSize]byte
- HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records.
- HasKM bool // cipher message (KM)
- HasKMA bool // cipher message assist (KMA)
- HasKMC bool // cipher message with chaining (KMC)
- HasKMCTR bool // cipher message with counter (KMCTR)
- HasKIMD bool // compute intermediate message digest (KIMD)
- _ [CacheLineSize]byte
+ _ [CacheLineSize]byte
+ HasZArch bool // z architecture mode is active [mandatory]
+ HasSTFLE bool // store facility list extended [mandatory]
+ HasLDisp bool // long (20-bit) displacements [mandatory]
+ HasEImm bool // 32-bit immediates [mandatory]
+ HasDFP bool // decimal floating point
+ HasETF3Enhanced bool // ETF-3 enhanced
+ HasMSA bool // message security assist (CPACF)
+ HasAES bool // KM-AES{128,192,256} functions
+ HasAESCBC bool // KMC-AES{128,192,256} functions
+ HasAESCTR bool // KMCTR-AES{128,192,256} functions
+ HasAESGCM bool // KMA-GCM-AES{128,192,256} functions
+ HasGHASH bool // KIMD-GHASH function
+ HasSHA1 bool // K{I,L}MD-SHA-1 functions
+ HasSHA256 bool // K{I,L}MD-SHA-256 functions
+ HasSHA512 bool // K{I,L}MD-SHA-512 functions
+ HasVX bool // vector facility. Note: the runtime sets this when it processes auxv records.
+ _ [CacheLineSize]byte
}
// initialize examines the processor and sets the relevant variables above.
diff --git a/src/internal/cpu/cpu_no_init.go b/src/internal/cpu/cpu_no_init.go
index 010cbcdb5e..1be4f29ddd 100644
--- a/src/internal/cpu/cpu_no_init.go
+++ b/src/internal/cpu/cpu_no_init.go
@@ -8,6 +8,7 @@
// +build !arm64
// +build !ppc64
// +build !ppc64le
+// +build !s390x
package cpu
diff --git a/src/internal/cpu/cpu_s390x.go b/src/internal/cpu/cpu_s390x.go
index 7b78289467..389a058c32 100644
--- a/src/internal/cpu/cpu_s390x.go
+++ b/src/internal/cpu/cpu_s390x.go
@@ -6,17 +6,148 @@ package cpu
const CacheLineSize = 256
-// the following cpu feature detection functions are defined in cpu_s390x.s
-func hasKM() bool
-func hasKMC() bool
-func hasKMCTR() bool
-func hasKMA() bool
-func hasKIMD() bool
-
-func init() {
- S390X.HasKM = hasKM()
- S390X.HasKMC = hasKMC()
- S390X.HasKMCTR = hasKMCTR()
- S390X.HasKMA = hasKMA()
- S390X.HasKIMD = hasKIMD()
+// bitIsSet reports whether the bit at index is set. The bit index
+// is in big endian order, so bit index 0 is the leftmost bit.
+func bitIsSet(bits []uint64, index uint) bool {
+ return bits[index/64]&((1<<63)>>(index%64)) != 0
+}
+
+// function is the function code for the named function.
+type function uint8
+
+const (
+ // KM{,A,C,CTR} function codes
+ aes128 function = 18 // AES-128
+ aes192 = 19 // AES-192
+ aes256 = 20 // AES-256
+
+ // K{I,L}MD function codes
+ sha1 = 1 // SHA-1
+ sha256 = 2 // SHA-256
+ sha512 = 3 // SHA-512
+
+ // KLMD function codes
+ ghash = 65 // GHASH
+)
+
+// queryResult contains the result of a Query function
+// call. Bits are numbered in big endian order so the
+// leftmost bit (the MSB) is at index 0.
+type queryResult struct {
+ bits [2]uint64
+}
+
+// Has reports whether the given functions are present.
+func (q *queryResult) Has(fns ...function) bool {
+ if len(fns) == 0 {
+ panic("no function codes provided")
+ }
+ for _, f := range fns {
+ if !bitIsSet(q.bits[:], uint(f)) {
+ return false
+ }
+ }
+ return true
+}
+
+// facility is a bit index for the named facility.
+type facility uint8
+
+const (
+ // mandatory facilities
+ zarch facility = 1 // z architecture mode is active
+ stflef = 7 // store-facility-list-extended
+ ldisp = 18 // long-displacement
+ eimm = 21 // extended-immediate
+
+ // miscellaneous facilities
+ dfp = 42 // decimal-floating-point
+ etf3eh = 30 // extended-translation 3 enhancement
+
+ // cryptography facilities
+ msa = 17 // message-security-assist
+ msa3 = 76 // message-security-assist extension 3
+ msa4 = 77 // message-security-assist extension 4
+ msa5 = 57 // message-security-assist extension 5
+ msa8 = 146 // message-security-assist extension 8
+
+ // Note: vx and highgprs are excluded because they require
+ // kernel support and so must be fetched from HWCAP.
+)
+
+// facilityList contains the result of an STFLE call.
+// Bits are numbered in big endian order so the
+// leftmost bit (the MSB) is at index 0.
+type facilityList struct {
+ bits [4]uint64
+}
+
+// Has reports whether the given facilities are present.
+func (s *facilityList) Has(fs ...facility) bool {
+ if len(fs) == 0 {
+ panic("no facility bits provided")
+ }
+ for _, f := range fs {
+ if !bitIsSet(s.bits[:], uint(f)) {
+ return false
+ }
+ }
+ return true
+}
+
+// The following feature detection functions are defined in cpu_s390x.s.
+// They are likely to be expensive to call so the results should be cached.
+func stfle() facilityList
+func kmQuery() queryResult
+func kmcQuery() queryResult
+func kmctrQuery() queryResult
+func kmaQuery() queryResult
+func kimdQuery() queryResult
+func klmdQuery() queryResult
+
+func doinit() {
+ options = []option{
+ {"zarch", &S390X.HasZArch},
+ {"stfle", &S390X.HasSTFLE},
+ {"ldisp", &S390X.HasLDisp},
+ {"msa", &S390X.HasMSA},
+ {"eimm", &S390X.HasEImm},
+ {"dfp", &S390X.HasDFP},
+ {"etf3eh", &S390X.HasETF3Enhanced},
+ {"vx", &S390X.HasVX},
+ }
+
+ aes := []function{aes128, aes192, aes256}
+ facilities := stfle()
+
+ S390X.HasZArch = facilities.Has(zarch)
+ S390X.HasSTFLE = facilities.Has(stflef)
+ S390X.HasLDisp = facilities.Has(ldisp)
+ S390X.HasEImm = facilities.Has(eimm)
+ S390X.HasDFP = facilities.Has(dfp)
+ S390X.HasETF3Enhanced = facilities.Has(etf3eh)
+ S390X.HasMSA = facilities.Has(msa)
+
+ if S390X.HasMSA {
+ // cipher message
+ km, kmc := kmQuery(), kmcQuery()
+ S390X.HasAES = km.Has(aes...)
+ S390X.HasAESCBC = kmc.Has(aes...)
+ if facilities.Has(msa4) {
+ kmctr := kmctrQuery()
+ S390X.HasAESCTR = kmctr.Has(aes...)
+ }
+ if facilities.Has(msa8) {
+ kma := kmaQuery()
+ S390X.HasAESGCM = kma.Has(aes...)
+ }
+
+ // compute message digest
+ kimd := kimdQuery() // intermediate (no padding)
+ klmd := klmdQuery() // last (padding)
+ S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1)
+ S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256)
+ S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512)
+ S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist
+ }
}
diff --git a/src/internal/cpu/cpu_s390x.s b/src/internal/cpu/cpu_s390x.s
index 04edb2ed0f..9678035ffb 100644
--- a/src/internal/cpu/cpu_s390x.s
+++ b/src/internal/cpu/cpu_s390x.s
@@ -4,98 +4,52 @@
#include "textflag.h"
-// func hasKM() bool
-TEXT ·hasKM(SB),NOSPLIT,$16-1
- XOR R0, R0 // set function code to 0 (query)
- LA mask-16(SP), R1 // 16-byte stack variable for mask
- MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
-
- // check for KM AES functions
- WORD $0xB92E0024 // cipher message (KM)
- MOVD mask-16(SP), R2
- AND R3, R2
- CMPBNE R2, R3, notfound
-
- MOVB $1, ret+0(FP)
+// func stfle() facilityList
+TEXT ·stfle(SB), NOSPLIT|NOFRAME, $0-32
+ MOVD $ret+0(FP), R1
+ MOVD $3, R0 // last doubleword index to store
+ XC $32, (R1), (R1) // clear 4 doublewords (32 bytes)
+ WORD $0xb2b01000 // store facility list extended (STFLE)
RET
-notfound:
- MOVB $0, ret+0(FP)
- RET
-
-// func hasKMC() bool
-TEXT ·hasKMC(SB),NOSPLIT,$16-1
- XOR R0, R0 // set function code to 0 (query)
- LA mask-16(SP), R1 // 16-byte stack variable for mask
- MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
- // check for KMC AES functions
- WORD $0xB92F0024 // cipher message with chaining (KMC)
- MOVD mask-16(SP), R2
- AND R3, R2
- CMPBNE R2, R3, notfound
-
- MOVB $1, ret+0(FP)
- RET
-notfound:
- MOVB $0, ret+0(FP)
+// func kmQuery() queryResult
+TEXT ·kmQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KM-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xB92E0024 // cipher message (KM)
RET
-// func hasKMCTR() bool
-TEXT ·hasKMCTR(SB),NOSPLIT,$16-1
- XOR R0, R0 // set function code to 0 (query)
- LA mask-16(SP), R1 // 16-byte stack variable for mask
- MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
-
- // check for KMCTR AES functions
- WORD $0xB92D4024 // cipher message with counter (KMCTR)
- MOVD mask-16(SP), R2
- AND R3, R2
- CMPBNE R2, R3, notfound
-
- MOVB $1, ret+0(FP)
- RET
-notfound:
- MOVB $0, ret+0(FP)
+// func kmcQuery() queryResult
+TEXT ·kmcQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KMC-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xB92F0024 // cipher message with chaining (KMC)
RET
-// func hasKMA() bool
-TEXT ·hasKMA(SB),NOSPLIT,$24-1
- MOVD $tmp-24(SP), R1
- MOVD $2, R0 // store 24-bytes
- XC $24, (R1), (R1)
- WORD $0xb2b01000 // STFLE (R1)
- MOVWZ 16(R1), R2
- ANDW $(1<<13), R2 // test bit 146 (message-security-assist 8)
- BEQ no
-
- MOVD $0, R0 // KMA-Query
- XC $16, (R1), (R1)
- WORD $0xb9296024 // kma %r6,%r2,%r4
- MOVWZ (R1), R2
- WORD $0xa7213800 // TMLL R2, $0x3800
- BVS yes
-no:
- MOVB $0, ret+0(FP)
- RET
-yes:
- MOVB $1, ret+0(FP)
+// func kmctrQuery() queryResult
+TEXT ·kmctrQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KMCTR-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xB92D4024 // cipher message with counter (KMCTR)
RET
-// func hasKIMD() bool
-TEXT ·hasKIMD(SB),NOSPLIT,$16-1
- XOR R0, R0 // set function code to 0 (query)
- LA mask-16(SP), R1 // 16-byte stack variable for mask
- MOVD $(0x38<<40), R3 // mask for bits 18-20 (big endian)
-
- // check for KIMD GHASH function
- WORD $0xB93E0024 // compute intermediate message digest (KIMD)
- MOVD mask-8(SP), R2 // bits 64-127
- MOVD $(1<<62), R5
- AND R5, R2
- CMPBNE R2, R5, notfound
+// func kmaQuery() queryResult
+TEXT ·kmaQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KMA-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xb9296024 // cipher message with authentication (KMA)
+ RET
- MOVB $1, ret+0(FP)
+// func kimdQuery() queryResult
+TEXT ·kimdQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KIMD-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xB93E0024 // compute intermediate message digest (KIMD)
RET
-notfound:
- MOVB $0, ret+0(FP)
+
+// func klmdQuery() queryResult
+TEXT ·klmdQuery(SB), NOSPLIT|NOFRAME, $0-16
+ MOVD $0, R0 // set function code to 0 (KLMD-Query)
+ MOVD $ret+0(FP), R1 // address of 16-byte return value
+ WORD $0xB93F0024 // compute last message digest (KLMD)
RET
diff --git a/src/internal/cpu/cpu_s390x_test.go b/src/internal/cpu/cpu_s390x_test.go
new file mode 100644
index 0000000000..d910bbe695
--- /dev/null
+++ b/src/internal/cpu/cpu_s390x_test.go
@@ -0,0 +1,63 @@
+// Copyright 2018 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 cpu_test
+
+import (
+ "errors"
+ . "internal/cpu"
+ "io/ioutil"
+ "regexp"
+ "testing"
+)
+
+func getFeatureList() ([]string, error) {
+ cpuinfo, err := ioutil.ReadFile("/proc/cpuinfo")
+ if err != nil {
+ return nil, err
+ }
+ r := regexp.MustCompile("features\\s*:\\s*(.*)")
+ b := r.FindSubmatch(cpuinfo)
+ if len(b) < 2 {
+ return nil, errors.New("no feature list in /proc/cpuinfo")
+ }
+ return regexp.MustCompile("\\s+").Split(string(b[1]), -1), nil
+}
+
+func TestS390XAgainstCPUInfo(t *testing.T) {
+ // mapping of linux feature strings to S390X fields
+ mapping := make(map[string]*bool)
+ for _, option := range Options {
+ mapping[option.Name] = option.Feature
+ }
+
+ // these must be true on the machines Go supports
+ mandatory := make(map[string]bool)
+ mandatory["zarch"] = false
+ mandatory["eimm"] = false
+ mandatory["ldisp"] = false
+ mandatory["stfle"] = false
+
+ features, err := getFeatureList()
+ if err != nil {
+ t.Error(err)
+ }
+ for _, feature := range features {
+ if _, ok := mandatory[feature]; ok {
+ mandatory[feature] = true
+ }
+ if flag, ok := mapping[feature]; ok {
+ if !*flag {
+ t.Errorf("feature '%v' not detected", feature)
+ }
+ } else {
+ t.Logf("no entry for '%v'", feature)
+ }
+ }
+ for k, v := range mandatory {
+ if !v {
+ t.Errorf("mandatory feature '%v' not detected", k)
+ }
+ }
+}
diff --git a/src/internal/poll/fd_mutex.go b/src/internal/poll/fd_mutex.go
index 2ba7de7da3..0a8ee6f0d4 100644
--- a/src/internal/poll/fd_mutex.go
+++ b/src/internal/poll/fd_mutex.go
@@ -34,6 +34,8 @@ const (
mutexWMask = (1<<20 - 1) << 43
)
+const overflowMsg = "too many concurrent operations on a single file or socket (max 1048575)"
+
// Read operations must do rwlock(true)/rwunlock(true).
//
// Write operations must do rwlock(false)/rwunlock(false).
@@ -56,7 +58,7 @@ func (mu *fdMutex) incref() bool {
}
new := old + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
if atomic.CompareAndSwapUint64(&mu.state, old, new) {
return true
@@ -75,7 +77,7 @@ func (mu *fdMutex) increfAndClose() bool {
// Mark as closed and acquire a reference.
new := (old | mutexClosed) + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
// Remove all read and write waiters.
new &^= mutexRMask | mutexWMask
@@ -136,13 +138,13 @@ func (mu *fdMutex) rwlock(read bool) bool {
// Lock is free, acquire it.
new = (old | mutexBit) + mutexRef
if new&mutexRefMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
} else {
// Wait for lock.
new = old + mutexWait
if new&mutexMask == 0 {
- panic("inconsistent poll.fdMutex")
+ panic(overflowMsg)
}
}
if atomic.CompareAndSwapUint64(&mu.state, old, new) {
diff --git a/src/internal/poll/fd_mutex_test.go b/src/internal/poll/fd_mutex_test.go
index bab81c6dfe..2c53c4561f 100644
--- a/src/internal/poll/fd_mutex_test.go
+++ b/src/internal/poll/fd_mutex_test.go
@@ -8,6 +8,7 @@ import (
. "internal/poll"
"math/rand"
"runtime"
+ "strings"
"testing"
"time"
)
@@ -121,6 +122,27 @@ func TestMutexPanic(t *testing.T) {
mu.RWUnlock(false)
}
+func TestMutexOverflowPanic(t *testing.T) {
+ defer func() {
+ r := recover()
+ if r == nil {
+ t.Fatal("did not panic")
+ }
+ msg, ok := r.(string)
+ if !ok {
+ t.Fatalf("unexpected panic type %T", r)
+ }
+ if !strings.Contains(msg, "too many") || strings.Contains(msg, "inconsistent") {
+ t.Fatalf("wrong panic message %q", msg)
+ }
+ }()
+
+ var mu1 FDMutex
+ for i := 0; i < 1<<21; i++ {
+ mu1.Incref()
+ }
+}
+
func TestMutexStress(t *testing.T) {
P := 8
N := int(1e6)
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
index 5a196e7efe..c10ac89496 100644
--- a/src/internal/poll/fd_unix.go
+++ b/src/internal/poll/fd_unix.go
@@ -9,6 +9,7 @@ package poll
import (
"io"
"runtime"
+ "sync/atomic"
"syscall"
)
@@ -102,6 +103,8 @@ func (fd *FD) Close() error {
// reference, it is already closed. Only wait if the file has
// not been set to blocking mode, as otherwise any current I/O
// may be blocking, and that would block the Close.
+ // No need for a lock to read isBlocking, increfAndClose means
+ // we have exclusive access to fd.
if !fd.isBlocking {
runtime_Semacquire(&fd.csema)
}
@@ -120,10 +123,12 @@ func (fd *FD) Shutdown(how int) error {
// SetBlocking puts the file into blocking mode.
func (fd *FD) SetBlocking() error {
- if err := fd.incref(); err != nil {
+ // Take an exclusive lock, rather than calling incref, so that
+ // we can safely modify isBlocking.
+ if err := fd.readLock(); err != nil {
return err
}
- defer fd.decref()
+ defer fd.readUnlock()
fd.isBlocking = true
return syscall.SetNonblock(fd.Sysfd, false)
}
@@ -439,6 +444,51 @@ func (fd *FD) Fstat(s *syscall.Stat_t) error {
return syscall.Fstat(fd.Sysfd, s)
}
+// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
+// If the kernel doesn't support it, this is set to 0.
+var tryDupCloexec = int32(1)
+
+// DupCloseOnExec dups fd and marks it close-on-exec.
+func DupCloseOnExec(fd int) (int, string, error) {
+ if atomic.LoadInt32(&tryDupCloexec) == 1 {
+ r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
+ switch e1 {
+ case 0:
+ return int(r0), "", nil
+ case syscall.EINVAL, syscall.ENOSYS:
+ // Old kernel, or js/wasm (which returns
+ // ENOSYS). Fall back to the portable way from
+ // now on.
+ atomic.StoreInt32(&tryDupCloexec, 0)
+ default:
+ return -1, "fcntl", e1
+ }
+ }
+ return dupCloseOnExecOld(fd)
+}
+
+// dupCloseOnExecUnixOld is the traditional way to dup an fd and
+// set its O_CLOEXEC bit, using two system calls.
+func dupCloseOnExecOld(fd int) (int, string, error) {
+ syscall.ForkLock.RLock()
+ defer syscall.ForkLock.RUnlock()
+ newfd, err := syscall.Dup(fd)
+ if err != nil {
+ return -1, "dup", err
+ }
+ syscall.CloseOnExec(newfd)
+ return newfd, "", nil
+}
+
+// Dup duplicates the file descriptor.
+func (fd *FD) Dup() (int, string, error) {
+ if err := fd.incref(); err != nil {
+ return -1, "", err
+ }
+ defer fd.decref()
+ return DupCloseOnExec(fd.Sysfd)
+}
+
// On Unix variants only, expose the IO event for the net code.
// WaitWrite waits until data can be read from fd.
diff --git a/src/internal/poll/sendfile_windows.go b/src/internal/poll/sendfile_windows.go
index 4a15b75236..1a4d0ca191 100644
--- a/src/internal/poll/sendfile_windows.go
+++ b/src/internal/poll/sendfile_windows.go
@@ -25,6 +25,16 @@ func SendFile(fd *FD, src syscall.Handle, n int64) (int64, error) {
o := &fd.wop
o.qty = uint32(n)
o.handle = src
+
+ // TODO(brainman): skip calling syscall.Seek if OS allows it
+ curpos, err := syscall.Seek(o.handle, 0, 1)
+ if err != nil {
+ return 0, err
+ }
+
+ o.o.OffsetHigh = uint32(curpos)
+ o.o.Offset = uint32(curpos >> 32)
+
done, err := wsrv.ExecIO(o, func(o *operation) error {
return syscall.TransmitFile(o.fd.Sysfd, o.handle, o.qty, 0, &o.o, nil, syscall.TF_WRITE_BEHIND)
})
diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go
index 5874f79a56..aa237e587a 100644
--- a/src/internal/poll/splice_linux.go
+++ b/src/internal/poll/splice_linux.go
@@ -34,20 +34,6 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string,
defer destroyTempPipe(prfd, pwfd)
// From here on, the operation should be considered handled,
// even if Splice doesn't transfer any data.
- if err := src.readLock(); err != nil {
- return 0, true, "splice", err
- }
- defer src.readUnlock()
- if err := dst.writeLock(); err != nil {
- return 0, true, "splice", err
- }
- defer dst.writeUnlock()
- if err := src.pd.prepareRead(src.isFile); err != nil {
- return 0, true, "splice", err
- }
- if err := dst.pd.prepareWrite(dst.isFile); err != nil {
- return 0, true, "splice", err
- }
var inPipe, n int
for err == nil && remain > 0 {
max := maxSpliceSize
@@ -84,6 +70,13 @@ func Splice(dst, src *FD, remain int64) (written int64, handled bool, sc string,
//
// If spliceDrain returns (0, nil), src is at EOF.
func spliceDrain(pipefd int, sock *FD, max int) (int, error) {
+ if err := sock.readLock(); err != nil {
+ return 0, err
+ }
+ defer sock.readUnlock()
+ if err := sock.pd.prepareRead(sock.isFile); err != nil {
+ return 0, err
+ }
for {
n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock)
if err != syscall.EAGAIN {
@@ -109,6 +102,13 @@ func spliceDrain(pipefd int, sock *FD, max int) (int, error) {
// all of it to the socket. This behavior is similar to the Write
// step of an io.Copy in userspace.
func splicePump(sock *FD, pipefd int, inPipe int) (int, error) {
+ if err := sock.writeLock(); err != nil {
+ return 0, err
+ }
+ defer sock.writeUnlock()
+ if err := sock.pd.prepareWrite(sock.isFile); err != nil {
+ return 0, err
+ }
written := 0
for inPipe > 0 {
n, err := splice(sock.Sysfd, pipefd, inPipe, spliceNonblock)
diff --git a/src/internal/syscall/unix/nonblocking_js.go b/src/internal/syscall/unix/nonblocking_js.go
index ff67c75e81..a360b53c3d 100644
--- a/src/internal/syscall/unix/nonblocking_js.go
+++ b/src/internal/syscall/unix/nonblocking_js.go
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
+// +build js,wasm
+
package unix
func IsNonblock(fd int) (nonblocking bool, err error) {
diff --git a/src/internal/syscall/windows/registry/zsyscall_windows.go b/src/internal/syscall/windows/registry/zsyscall_windows.go
index a3a1f5fc8f..c3f3a8a215 100644
--- a/src/internal/syscall/windows/registry/zsyscall_windows.go
+++ b/src/internal/syscall/windows/registry/zsyscall_windows.go
@@ -1,4 +1,4 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// Code generated by 'go generate'; DO NOT EDIT.
package registry
diff --git a/src/internal/syscall/windows/zsyscall_windows.go b/src/internal/syscall/windows/zsyscall_windows.go
index 296ee9c1ce..550a8a5bd4 100644
--- a/src/internal/syscall/windows/zsyscall_windows.go
+++ b/src/internal/syscall/windows/zsyscall_windows.go
@@ -1,4 +1,4 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// Code generated by 'go generate'; DO NOT EDIT.
package windows
diff --git a/src/make.bash b/src/make.bash
index 4ea5a9a8b5..a28b82a058 100755
--- a/src/make.bash
+++ b/src/make.bash
@@ -141,7 +141,7 @@ export GOROOT_BOOTSTRAP=${GOROOT_BOOTSTRAP:-$HOME/go1.4}
export GOROOT="$(cd .. && pwd)"
IFS=$'\n'; for go_exe in $(type -ap go); do
if [ ! -x "$GOROOT_BOOTSTRAP/bin/go" ]; then
- goroot=$(GOROOT='' "$go_exe" env GOROOT)
+ goroot=$(GOROOT='' GOOS='' GOARCH='' "$go_exe" env GOROOT)
if [ "$goroot" != "$GOROOT" ]; then
GOROOT_BOOTSTRAP=$goroot
fi
diff --git a/src/math/big/float.go b/src/math/big/float.go
index 6f0025ec57..55b93c8915 100644
--- a/src/math/big/float.go
+++ b/src/math/big/float.go
@@ -1429,8 +1429,6 @@ func (x *Float) ucmp(y *Float) int {
// z's accuracy reports the result error relative to the exact (not rounded)
// result. Add panics with ErrNaN if x and y are infinities with opposite
// signs. The value of z is undefined in that case.
-//
-// BUG(gri) When rounding ToNegativeInf, the sign of Float values rounded to 0 is incorrect.
func (z *Float) Add(x, y *Float) *Float {
if debugFloat {
x.validate()
@@ -1466,6 +1464,9 @@ func (z *Float) Add(x, y *Float) *Float {
z.usub(y, x)
}
}
+ if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
+ z.neg = true
+ }
return z
}
@@ -1530,6 +1531,9 @@ func (z *Float) Sub(x, y *Float) *Float {
z.usub(y, x)
}
}
+ if z.form == zero && z.mode == ToNegativeInf && z.acc == Exact {
+ z.neg = true
+ }
return z
}
diff --git a/src/math/big/float_test.go b/src/math/big/float_test.go
index 2029409656..7d6bf034df 100644
--- a/src/math/big/float_test.go
+++ b/src/math/big/float_test.go
@@ -1258,6 +1258,31 @@ func TestFloatAdd(t *testing.T) {
}
}
+// TestFloatAddRoundZero tests Float.Add/Sub rounding when the result is exactly zero.
+// x + (-x) or x - x for non-zero x should be +0 in all cases except when
+// the rounding mode is ToNegativeInf in which case it should be -0.
+func TestFloatAddRoundZero(t *testing.T) {
+ for _, mode := range [...]RoundingMode{ToNearestEven, ToNearestAway, ToZero, AwayFromZero, ToPositiveInf, ToNegativeInf} {
+ x := NewFloat(5.0)
+ y := new(Float).Neg(x)
+ want := NewFloat(0.0)
+ if mode == ToNegativeInf {
+ want.Neg(want)
+ }
+ got := new(Float).SetMode(mode)
+ got.Add(x, y)
+ if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) {
+ t.Errorf("%s:\n\t %v\n\t+ %v\n\t= %v\n\twant %v",
+ mode, x, y, got, want)
+ }
+ got.Sub(x, x)
+ if got.Cmp(want) != 0 || got.neg != (mode == ToNegativeInf) {
+ t.Errorf("%v:\n\t %v\n\t- %v\n\t= %v\n\twant %v",
+ mode, x, x, got, want)
+ }
+ }
+}
+
// TestFloatAdd32 tests that Float.Add/Sub of numbers with
// 24bit mantissa behaves like float32 addition/subtraction
// (excluding denormal numbers).
diff --git a/src/math/big/int.go b/src/math/big/int.go
index d46b5d8a86..47a288ab44 100644
--- a/src/math/big/int.go
+++ b/src/math/big/int.go
@@ -442,24 +442,28 @@ func (x *Int) BitLen() int {
}
// Exp sets z = x**y mod |m| (i.e. the sign of m is ignored), and returns z.
-// If y <= 0, the result is 1 mod |m|; if m == nil or m == 0, z = x**y.
+// If m == nil or m == 0, z = x**y unless y <= 0 then z = 1.
//
// Modular exponentation of inputs of a particular size is not a
// cryptographically constant-time operation.
func (z *Int) Exp(x, y, m *Int) *Int {
// See Knuth, volume 2, section 4.6.3.
- var yWords nat
- if !y.neg {
- yWords = y.abs
+ xWords := x.abs
+ if y.neg {
+ if m == nil || len(m.abs) == 0 {
+ return z.SetInt64(1)
+ }
+ // for y < 0: x**y mod m == (x**(-1))**|y| mod m
+ xWords = new(Int).ModInverse(x, m).abs
}
- // y >= 0
+ yWords := y.abs
var mWords nat
if m != nil {
mWords = m.abs // m.abs may be nil for m == 0
}
- z.abs = z.abs.expNN(x.abs, yWords, mWords)
+ z.abs = z.abs.expNN(xWords, yWords, mWords)
z.neg = len(z.abs) > 0 && x.neg && len(yWords) > 0 && yWords[0]&1 == 1 // 0 has no sign
if z.neg && len(mWords) > 0 {
// make modulus result positive
diff --git a/src/math/big/int_test.go b/src/math/big/int_test.go
index 111e2de573..9930ed016a 100644
--- a/src/math/big/int_test.go
+++ b/src/math/big/int_test.go
@@ -557,7 +557,7 @@ var expTests = []struct {
{"0x8000000000000000", "3", "6719", "5447"},
{"0x8000000000000000", "1000", "6719", "1603"},
{"0x8000000000000000", "1000000", "6719", "3199"},
- {"0x8000000000000000", "-1000000", "6719", "1"},
+ {"0x8000000000000000", "-1000000", "6719", "3663"}, // 3663 = ModInverse(3199, 6719) Issue #25865
{"0xffffffffffffffffffffffffffffffff", "0x12345678123456781234567812345678123456789", "0x01112222333344445555666677778889", "0x36168FA1DB3AAE6C8CE647E137F97A"},
diff --git a/src/math/example_test.go b/src/math/example_test.go
index feaf9d8252..a1f764bcda 100644
--- a/src/math/example_test.go
+++ b/src/math/example_test.go
@@ -89,3 +89,27 @@ func ExampleSqrt() {
fmt.Printf("%.1f", c)
// Output: 5.0
}
+
+func ExampleCeil() {
+ c := math.Ceil(1.49)
+ fmt.Printf("%.1f", c)
+ // Output: 2.0
+}
+
+func ExampleFloor() {
+ c := math.Floor(1.51)
+ fmt.Printf("%.1f", c)
+ // Output: 1.0
+}
+
+func ExamplePow() {
+ c := math.Pow(2, 3)
+ fmt.Printf("%.1f", c)
+ // Output: 8.0
+}
+
+func ExamplePow10() {
+ c := math.Pow10(2)
+ fmt.Printf("%.1f", c)
+ // Output: 100.0
+}
diff --git a/src/mime/multipart/formdata.go b/src/mime/multipart/formdata.go
index 22e2c8d323..832d0ad693 100644
--- a/src/mime/multipart/formdata.go
+++ b/src/mime/multipart/formdata.go
@@ -58,7 +58,7 @@ func (r *Reader) readForm(maxMemory int64) (_ *Form, err error) {
var b bytes.Buffer
- if !p.hasFileName() {
+ if filename == "" {
// value, store as string in memory
n, err := io.CopyN(&b, p, maxValueBytes+1)
if err != nil && err != io.EOF {
diff --git a/src/mime/multipart/formdata_test.go b/src/mime/multipart/formdata_test.go
index 5e3c3330f3..2d6a830cb6 100644
--- a/src/mime/multipart/formdata_test.go
+++ b/src/mime/multipart/formdata_test.go
@@ -47,12 +47,9 @@ func TestReadFormWithNamelessFile(t *testing.T) {
}
defer f.RemoveAll()
- fd := testFile(t, f.File["hiddenfile"][0], "", filebContents)
- if _, ok := fd.(sectionReadCloser); !ok {
- t.Errorf("file has unexpected underlying type %T", fd)
+ if g, e := f.Value["hiddenfile"][0], filebContents; g != e {
+ t.Errorf("hiddenfile value = %q, want %q", g, e)
}
- fd.Close()
-
}
func TestReadFormWithTextContentType(t *testing.T) {
diff --git a/src/mime/multipart/multipart.go b/src/mime/multipart/multipart.go
index adaaf6975a..0993fb7e91 100644
--- a/src/mime/multipart/multipart.go
+++ b/src/mime/multipart/multipart.go
@@ -81,16 +81,6 @@ func (p *Part) FileName() string {
return p.dispositionParams["filename"]
}
-// hasFileName determines if a (empty or otherwise)
-// filename parameter was included in the Content-Disposition header
-func (p *Part) hasFileName() bool {
- if p.dispositionParams == nil {
- p.parseContentDisposition()
- }
- _, ok := p.dispositionParams["filename"]
- return ok
-}
-
func (p *Part) parseContentDisposition() {
v := p.Header.Get("Content-Disposition")
var err error
@@ -313,7 +303,9 @@ func (r *Reader) NextPart() (*Part, error) {
if r.currentPart != nil {
r.currentPart.Close()
}
-
+ if string(r.dashBoundary) == "--" {
+ return nil, fmt.Errorf("multipart: boundary is empty")
+ }
expectNewPart := false
for {
line, err := r.bufReader.ReadSlice('\n')
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go
index 7fbee90ac3..abe1cc8e77 100644
--- a/src/mime/multipart/multipart_test.go
+++ b/src/mime/multipart/multipart_test.go
@@ -880,3 +880,11 @@ func roundTripParseTest() parseTest {
t.sep = w.Boundary()
return t
}
+
+func TestNoBoundary(t *testing.T) {
+ mr := NewReader(strings.NewReader(""), "")
+ _, err := mr.NextPart()
+ if got, want := fmt.Sprint(err), "multipart: boundary is empty"; got != want {
+ t.Errorf("NextPart error = %v; want %v", got, want)
+ }
+}
diff --git a/src/mime/quotedprintable/reader.go b/src/mime/quotedprintable/reader.go
index b142240343..4239625402 100644
--- a/src/mime/quotedprintable/reader.go
+++ b/src/mime/quotedprintable/reader.go
@@ -123,6 +123,10 @@ func (r *Reader) Read(p []byte) (n int, err error) {
r.line = r.line[2:] // 2 of the 3; other 1 is done below
case b == '\t' || b == '\r' || b == '\n':
break
+ case b >= 0x80:
+ // As an extension to RFC 2045, we accept
+ // values >= 0x80 without complaint. Issue 22597.
+ break
case b < ' ' || b > '~':
return n, fmt.Errorf("quotedprintable: invalid unescaped byte 0x%02x in body", b)
}
diff --git a/src/mime/quotedprintable/reader_test.go b/src/mime/quotedprintable/reader_test.go
index ca016f969a..f870bdaa8d 100644
--- a/src/mime/quotedprintable/reader_test.go
+++ b/src/mime/quotedprintable/reader_test.go
@@ -37,7 +37,7 @@ func TestReader(t *testing.T) {
{in: " A B =\n C ", want: " A B C"}, // lax. treating LF as CRLF
{in: "foo=\nbar", want: "foobar"},
{in: "foo\x00bar", want: "foo", err: "quotedprintable: invalid unescaped byte 0x00 in body"},
- {in: "foo bar\xff", want: "foo bar", err: "quotedprintable: invalid unescaped byte 0xff in body"},
+ {in: "foo bar\xff", want: "foo bar\xff"},
// Equal sign.
{in: "=3D30\n", want: "=30\n"},
@@ -65,6 +65,8 @@ func TestReader(t *testing.T) {
// Example from RFC 2045:
{in: "Now's the time =\n" + "for all folk to come=\n" + " to the aid of their country.",
want: "Now's the time for all folk to come to the aid of their country."},
+ {in: "accept UTF-8 right quotation mark: ’",
+ want: "accept UTF-8 right quotation mark: ’"},
}
for _, tt := range tests {
var buf bytes.Buffer
diff --git a/src/mime/type.go b/src/mime/type.go
index 78fc6b6714..64e26ffb7c 100644
--- a/src/mime/type.go
+++ b/src/mime/type.go
@@ -62,7 +62,8 @@ var builtinTypesLower = map[string]string{
".htm": "text/html; charset=utf-8",
".html": "text/html; charset=utf-8",
".jpg": "image/jpeg",
- ".js": "application/x-javascript",
+ ".js": "application/javascript",
+ ".wasm": "application/wasm",
".pdf": "application/pdf",
".png": "image/png",
".svg": "image/svg+xml",
diff --git a/src/net/cgo_unix.go b/src/net/cgo_unix.go
index 1baa01f036..3db867a080 100644
--- a/src/net/cgo_unix.go
+++ b/src/net/cgo_unix.go
@@ -249,7 +249,7 @@ func cgoLookupPTR(ctx context.Context, addr string) (names []string, err error,
var zone string
ip := parseIPv4(addr)
if ip == nil {
- ip, zone = parseIPv6(addr, true)
+ ip, zone = parseIPv6Zone(addr)
}
if ip == nil {
return nil, &DNSError{Err: "invalid address", Name: addr}, true
diff --git a/src/net/dnsconfig_unix.go b/src/net/dnsconfig_unix.go
index 53fa14687f..707fd6f6fe 100644
--- a/src/net/dnsconfig_unix.go
+++ b/src/net/dnsconfig_unix.go
@@ -73,7 +73,7 @@ func dnsReadConfig(filename string) *dnsConfig {
// to look it up.
if parseIPv4(f[1]) != nil {
conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
- } else if ip, _ := parseIPv6(f[1], true); ip != nil {
+ } else if ip, _ := parseIPv6Zone(f[1]); ip != nil {
conf.servers = append(conf.servers, JoinHostPort(f[1], "53"))
}
}
diff --git a/src/net/example_test.go b/src/net/example_test.go
index 8126a28404..e4d732e68a 100644
--- a/src/net/example_test.go
+++ b/src/net/example_test.go
@@ -121,7 +121,8 @@ func ExampleIPv4Mask() {
}
func ExampleUDPConn_WriteTo() {
- // Create connection in non-pre-connected state
+ // Unlike Dial, ListenPacket creates a connection without any
+ // association with peers.
conn, err := net.ListenPacket("udp", ":0")
if err != nil {
log.Fatal(err)
@@ -133,7 +134,7 @@ func ExampleUDPConn_WriteTo() {
log.Fatal(err)
}
- // Write data to the desired address
+ // The connection can write data to the desired address.
_, err = conn.WriteTo([]byte("data"), dst)
if err != nil {
log.Fatal(err)
diff --git a/src/net/fd_unix.go b/src/net/fd_unix.go
index 84613c778c..055ecf0336 100644
--- a/src/net/fd_unix.go
+++ b/src/net/fd_unix.go
@@ -11,7 +11,6 @@ import (
"internal/poll"
"os"
"runtime"
- "sync/atomic"
"syscall"
"time"
)
@@ -23,7 +22,7 @@ type netFD struct {
// immutable until Close
family int
sotype int
- isConnected bool
+ isConnected bool // handshake completed or use of association with peer
net string
laddr Addr
raddr Addr
@@ -257,43 +256,12 @@ func (fd *netFD) accept() (netfd *netFD, err error) {
return netfd, nil
}
-// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
-// If the kernel doesn't support it, this is set to 0.
-var tryDupCloexec = int32(1)
-
-func dupCloseOnExec(fd int) (newfd int, err error) {
- if atomic.LoadInt32(&tryDupCloexec) == 1 {
- r0, _, e1 := syscall.Syscall(syscall.SYS_FCNTL, uintptr(fd), syscall.F_DUPFD_CLOEXEC, 0)
- switch e1 {
- case 0:
- return int(r0), nil
- case syscall.EINVAL:
- // Old kernel. Fall back to the portable way
- // from now on.
- atomic.StoreInt32(&tryDupCloexec, 0)
- default:
- return -1, os.NewSyscallError("fcntl", e1)
- }
- }
- return dupCloseOnExecOld(fd)
-}
-
-// dupCloseOnExecUnixOld is the traditional way to dup an fd and
-// set its O_CLOEXEC bit, using two system calls.
-func dupCloseOnExecOld(fd int) (newfd int, err error) {
- syscall.ForkLock.RLock()
- defer syscall.ForkLock.RUnlock()
- newfd, err = syscall.Dup(fd)
- if err != nil {
- return -1, os.NewSyscallError("dup", err)
- }
- syscall.CloseOnExec(newfd)
- return
-}
-
func (fd *netFD) dup() (f *os.File, err error) {
- ns, err := dupCloseOnExec(fd.pfd.Sysfd)
+ ns, call, err := fd.pfd.Dup()
if err != nil {
+ if call != "" {
+ err = os.NewSyscallError(call, err)
+ }
return nil, err
}
diff --git a/src/net/fd_windows.go b/src/net/fd_windows.go
index 8a91138a42..3cc4c7a6a2 100644
--- a/src/net/fd_windows.go
+++ b/src/net/fd_windows.go
@@ -32,7 +32,7 @@ type netFD struct {
// immutable until Close
family int
sotype int
- isConnected bool
+ isConnected bool // handshake completed or use of association with peer
net string
laddr Addr
raddr Addr
diff --git a/src/net/file_test.go b/src/net/file_test.go
index 9fb5f2fd26..cd717747af 100644
--- a/src/net/file_test.go
+++ b/src/net/file_test.go
@@ -293,3 +293,57 @@ func TestFilePacketConn(t *testing.T) {
}
}
}
+
+// Issue 24483.
+func TestFileCloseRace(t *testing.T) {
+ switch runtime.GOOS {
+ case "nacl", "plan9", "windows":
+ t.Skipf("not supported on %s", runtime.GOOS)
+ }
+ if !testableNetwork("tcp") {
+ t.Skip("tcp not supported")
+ }
+
+ handler := func(ls *localServer, ln Listener) {
+ c, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ defer c.Close()
+ var b [1]byte
+ c.Read(b[:])
+ }
+
+ ls, err := newLocalServer("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ls.teardown()
+ if err := ls.buildup(handler); err != nil {
+ t.Fatal(err)
+ }
+
+ const tries = 100
+ for i := 0; i < tries; i++ {
+ c1, err := Dial(ls.Listener.Addr().Network(), ls.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ tc := c1.(*TCPConn)
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ f, err := tc.File()
+ if err == nil {
+ f.Close()
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ c1.Close()
+ }()
+ wg.Wait()
+ }
+}
diff --git a/src/net/file_unix.go b/src/net/file_unix.go
index d67dff8e05..676798d693 100644
--- a/src/net/file_unix.go
+++ b/src/net/file_unix.go
@@ -13,8 +13,11 @@ import (
)
func dupSocket(f *os.File) (int, error) {
- s, err := dupCloseOnExec(int(f.Fd()))
+ s, call, err := poll.DupCloseOnExec(int(f.Fd()))
if err != nil {
+ if call != "" {
+ err = os.NewSyscallError(call, err)
+ }
return -1, err
}
if err := syscall.SetNonblock(s, true); err != nil {
diff --git a/src/net/hosts.go b/src/net/hosts.go
index 9c101c6ef5..ebc0353a7f 100644
--- a/src/net/hosts.go
+++ b/src/net/hosts.go
@@ -16,7 +16,7 @@ func parseLiteralIP(addr string) string {
var zone string
ip = parseIPv4(addr)
if ip == nil {
- ip, zone = parseIPv6(addr, true)
+ ip, zone = parseIPv6Zone(addr)
}
if ip == nil {
return ""
diff --git a/src/net/http/export_test.go b/src/net/http/export_test.go
index e0ceb40021..7c7b5d5667 100644
--- a/src/net/http/export_test.go
+++ b/src/net/http/export_test.go
@@ -198,8 +198,8 @@ func (s *Server) ExportAllConnsIdle() bool {
s.mu.Lock()
defer s.mu.Unlock()
for c := range s.activeConn {
- st, ok := c.curState.Load().(ConnState)
- if !ok || st != StateIdle {
+ st, unixSec := c.getState()
+ if unixSec == 0 || st != StateIdle {
return false
}
}
diff --git a/src/net/http/header.go b/src/net/http/header.go
index 622ad28963..461ae9368a 100644
--- a/src/net/http/header.go
+++ b/src/net/http/header.go
@@ -6,6 +6,7 @@ package http
import (
"io"
+ "net/http/httptrace"
"net/textproto"
"sort"
"strings"
@@ -56,7 +57,11 @@ func (h Header) Del(key string) {
// Write writes a header in wire format.
func (h Header) Write(w io.Writer) error {
- return h.WriteSubset(w, nil)
+ return h.write(w, nil)
+}
+
+func (h Header) write(w io.Writer, trace *httptrace.ClientTrace) error {
+ return h.writeSubset(w, nil, trace)
}
func (h Header) clone() Header {
@@ -145,11 +150,16 @@ func (h Header) sortedKeyValues(exclude map[string]bool) (kvs []keyValues, hs *h
// WriteSubset writes a header in wire format.
// If exclude is not nil, keys where exclude[key] == true are not written.
func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
+ return h.writeSubset(w, exclude, nil)
+}
+
+func (h Header) writeSubset(w io.Writer, exclude map[string]bool, trace *httptrace.ClientTrace) error {
ws, ok := w.(writeStringer)
if !ok {
ws = stringWriter{w}
}
kvs, sorter := h.sortedKeyValues(exclude)
+ var formattedVals []string
for _, kv := range kvs {
for _, v := range kv.values {
v = headerNewlineToSpace.Replace(v)
@@ -160,6 +170,13 @@ func (h Header) WriteSubset(w io.Writer, exclude map[string]bool) error {
return err
}
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ formattedVals = append(formattedVals, v)
+ }
+ }
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField(kv.key, formattedVals)
+ formattedVals = nil
}
}
headerSorterPool.Put(sorter)
diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go
index 22170cf98b..1d0310625b 100644
--- a/src/net/http/httptest/recorder.go
+++ b/src/net/http/httptest/recorder.go
@@ -27,9 +27,11 @@ type ResponseRecorder struct {
Code int
// HeaderMap contains the headers explicitly set by the Handler.
+ // It is an internal detail.
//
- // To get the implicit headers set by the server (such as
- // automatic Content-Type), use the Result method.
+ // Deprecated: HeaderMap exists for historical compatibility
+ // and should not be used. To access the headers returned by a handler,
+ // use the Response.Header map as returned by the Result method.
HeaderMap http.Header
// Body is the buffer to which the Handler's Write calls are sent.
diff --git a/src/net/http/httptrace/trace.go b/src/net/http/httptrace/trace.go
index ea7b38c8fc..3a627412b3 100644
--- a/src/net/http/httptrace/trace.go
+++ b/src/net/http/httptrace/trace.go
@@ -11,6 +11,7 @@ import (
"crypto/tls"
"internal/nettrace"
"net"
+ "net/textproto"
"reflect"
"time"
)
@@ -107,6 +108,12 @@ type ClientTrace struct {
// Continue" response.
Got100Continue func()
+ // Got1xxResponse is called for each 1xx informational response header
+ // returned before the final non-1xx response. Got1xxResponse is called
+ // for "100 Continue" responses, even if Got100Continue is also defined.
+ // If it returns an error, the client request is aborted with that error value.
+ Got1xxResponse func(code int, header textproto.MIMEHeader) error
+
// DNSStart is called when a DNS lookup begins.
DNSStart func(DNSStartInfo)
@@ -135,8 +142,13 @@ type ClientTrace struct {
// failure.
TLSHandshakeDone func(tls.ConnectionState, error)
+ // WroteHeaderField is called after the Transport has written
+ // each request header. At the time of this call the values
+ // might be buffered and not yet written to the network.
+ WroteHeaderField func(key string, value []string)
+
// WroteHeaders is called after the Transport has written
- // the request headers.
+ // all request headers.
WroteHeaders func()
// Wait100Continue is called if the Request specified
diff --git a/src/net/http/request.go b/src/net/http/request.go
index 7c4325027c..13c5417053 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -214,6 +214,11 @@ type Request struct {
// names, Host may be in Punycode or Unicode form. Use
// golang.org/x/net/idna to convert it to either format if
// needed.
+ // To prevent DNS rebinding attacks, server Handlers should
+ // validate that the Host header has a value for which the
+ // Handler considers itself authoritative. The included
+ // ServeMux supports patterns registered to particular host
+ // names and thus protects its registered Handlers.
//
// For client requests Host optionally overrides the Host
// header to send. If empty, the Request.Write method uses
@@ -316,8 +321,7 @@ type Request struct {
//
// For incoming server requests, the context is canceled when the
// client's connection closes, the request is canceled (with HTTP/2),
-// the ServeHTTP method returns, or if the Hijack method is
-// called on the ResponseWriter.
+// or when the ServeHTTP method returns.
func (r *Request) Context() context.Context {
if r.ctx != nil {
return r.ctx
@@ -551,6 +555,9 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
if err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("Host", []string{host})
+ }
// Use the defaultUserAgent unless the Header contains one, which
// may be blank to not send the header.
@@ -563,6 +570,9 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
if err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("User-Agent", []string{userAgent})
+ }
}
// Process Body,ContentLength,Close,Trailer
@@ -570,18 +580,18 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
if err != nil {
return err
}
- err = tw.WriteHeader(w)
+ err = tw.writeHeader(w, trace)
if err != nil {
return err
}
- err = r.Header.WriteSubset(w, reqWriteExcludeHeader)
+ err = r.Header.writeSubset(w, reqWriteExcludeHeader, trace)
if err != nil {
return err
}
if extraHeaders != nil {
- err = extraHeaders.Write(w)
+ err = extraHeaders.write(w, trace)
if err != nil {
return err
}
@@ -620,7 +630,7 @@ func (r *Request) write(w io.Writer, usingProxy bool, extraHeaders Header, waitF
}
// Write body and trailer
- err = tw.WriteBody(w)
+ err = tw.writeBody(w)
if err != nil {
if tw.bodyReadError == err {
err = requestBodyReadError{err}
diff --git a/src/net/http/response.go b/src/net/http/response.go
index 09674670b1..bf1e13c8ae 100644
--- a/src/net/http/response.go
+++ b/src/net/http/response.go
@@ -293,7 +293,7 @@ func (r *Response) Write(w io.Writer) error {
if err != nil {
return err
}
- err = tw.WriteHeader(w)
+ err = tw.writeHeader(w, nil)
if err != nil {
return err
}
@@ -319,7 +319,7 @@ func (r *Response) Write(w io.Writer) error {
}
// Write body and trailer
- err = tw.WriteBody(w)
+ err = tw.writeBody(w)
if err != nil {
return err
}
diff --git a/src/net/http/roundtrip_js.go b/src/net/http/roundtrip_js.go
index e99d418da4..336c413cea 100644
--- a/src/net/http/roundtrip_js.go
+++ b/src/net/http/roundtrip_js.go
@@ -22,28 +22,28 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
if useFakeNetwork() {
return t.roundTrip(req)
}
- headers := js.Global.Get("Headers").New()
+ headers := js.Global().Get("Headers").New()
for key, values := range req.Header {
for _, value := range values {
headers.Call("append", key, value)
}
}
- ac := js.Global.Get("AbortController")
- if ac != js.Undefined {
+ ac := js.Global().Get("AbortController")
+ if ac != js.Undefined() {
// Some browsers that support WASM don't necessarily support
// the AbortController. See
// https://developer.mozilla.org/en-US/docs/Web/API/AbortController#Browser_compatibility.
ac = ac.New()
}
- opt := js.Global.Get("Object").New()
+ opt := js.Global().Get("Object").New()
// See https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
// for options available.
opt.Set("headers", headers)
opt.Set("method", req.Method)
opt.Set("credentials", "same-origin")
- if ac != js.Undefined {
+ if ac != js.Undefined() {
opt.Set("signal", ac.Get("signal"))
}
@@ -62,7 +62,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
req.Body.Close()
opt.Set("body", body)
}
- respPromise := js.Global.Call("fetch", req.URL.String(), opt)
+ respPromise := js.Global().Call("fetch", req.URL.String(), opt)
var (
respCh = make(chan *Response, 1)
errCh = make(chan error, 1)
@@ -90,7 +90,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
b := result.Get("body")
var body io.ReadCloser
- if b != js.Undefined {
+ if b != js.Undefined() {
body = &streamReader{stream: b.Call("getReader")}
} else {
// Fall back to using ArrayBuffer
@@ -110,7 +110,7 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
case <-req.Context().Done():
}
})
- defer success.Close()
+ defer success.Release()
failure := js.NewCallback(func(args []js.Value) {
err := fmt.Errorf("net/http: fetch() failed: %s", args[0].String())
select {
@@ -118,11 +118,11 @@ func (t *Transport) RoundTrip(req *Request) (*Response, error) {
case <-req.Context().Done():
}
})
- defer failure.Close()
+ defer failure.Release()
respPromise.Call("then", success, failure)
select {
case <-req.Context().Done():
- if ac != js.Undefined {
+ if ac != js.Undefined() {
// Abort the Fetch request
ac.Call("abort")
}
@@ -166,10 +166,12 @@ func (r *streamReader) Read(p []byte) (n int, err error) {
return
}
value := make([]byte, result.Get("value").Get("byteLength").Int())
- js.ValueOf(value).Call("set", result.Get("value"))
+ a := js.TypedArrayOf(value)
+ a.Call("set", result.Get("value"))
+ a.Release()
bCh <- value
})
- defer success.Close()
+ defer success.Release()
failure := js.NewCallback(func(args []js.Value) {
// Assumes it's a TypeError. See
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
@@ -178,7 +180,7 @@ func (r *streamReader) Read(p []byte) (n int, err error) {
// the read method.
errCh <- errors.New(args[0].Get("message").String())
})
- defer failure.Close()
+ defer failure.Release()
r.stream.Call("read").Call("then", success, failure)
select {
case b := <-bCh:
@@ -225,12 +227,14 @@ func (r *arrayReader) Read(p []byte) (n int, err error) {
)
success := js.NewCallback(func(args []js.Value) {
// Wrap the input ArrayBuffer with a Uint8Array
- uint8arrayWrapper := js.Global.Get("Uint8Array").New(args[0])
+ uint8arrayWrapper := js.Global().Get("Uint8Array").New(args[0])
value := make([]byte, uint8arrayWrapper.Get("byteLength").Int())
- js.ValueOf(value).Call("set", uint8arrayWrapper)
+ a := js.TypedArrayOf(value)
+ a.Call("set", uint8arrayWrapper)
+ a.Release()
bCh <- value
})
- defer success.Close()
+ defer success.Release()
failure := js.NewCallback(func(args []js.Value) {
// Assumes it's a TypeError. See
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypeError
@@ -238,7 +242,7 @@ func (r *arrayReader) Read(p []byte) (n int, err error) {
// See https://fetch.spec.whatwg.org/#concept-body-consume-body for reasons this might error.
errCh <- errors.New(args[0].Get("message").String())
})
- defer failure.Close()
+ defer failure.Release()
r.arrayPromise.Call("then", success, failure)
select {
case b := <-bCh:
diff --git a/src/net/http/serve_test.go b/src/net/http/serve_test.go
index 10651fff7c..5ab17a649e 100644
--- a/src/net/http/serve_test.go
+++ b/src/net/http/serve_test.go
@@ -14,6 +14,7 @@ import (
"crypto/tls"
"encoding/json"
"errors"
+ "flag"
"fmt"
"internal/testenv"
"io"
@@ -5562,6 +5563,64 @@ func testServerShutdown(t *testing.T, h2 bool) {
}
}
+var slowTests = flag.Bool("slow", false, "run slow tests")
+
+func TestServerShutdownStateNew(t *testing.T) {
+ if !*slowTests {
+ t.Skip("skipping slow test without -slow flag")
+ }
+ setParallel(t)
+ defer afterTest(t)
+
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ // nothing.
+ }))
+ defer ts.Close()
+
+ // Start a connection but never write to it.
+ c, err := net.Dial("tcp", ts.Listener.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ shutdownRes := make(chan error, 1)
+ go func() {
+ shutdownRes <- ts.Config.Shutdown(context.Background())
+ }()
+ readRes := make(chan error, 1)
+ go func() {
+ _, err := c.Read([]byte{0})
+ readRes <- err
+ }()
+
+ const expectTimeout = 5 * time.Second
+ t0 := time.Now()
+ select {
+ case got := <-shutdownRes:
+ d := time.Since(t0)
+ if got != nil {
+ t.Fatalf("shutdown error after %v: %v", d, err)
+ }
+ if d < expectTimeout/2 {
+ t.Errorf("shutdown too soon after %v", d)
+ }
+ case <-time.After(expectTimeout * 3 / 2):
+ t.Fatalf("timeout waiting for shutdown")
+ }
+
+ // Wait for c.Read to unblock; should be already done at this point,
+ // or within a few milliseconds.
+ select {
+ case err := <-readRes:
+ if err == nil {
+ t.Error("expected error from Read")
+ }
+ case <-time.After(2 * time.Second):
+ t.Errorf("timeout waiting for Read to unblock")
+ }
+}
+
// Issue 17878: tests that we can call Close twice.
func TestServerCloseDeadlock(t *testing.T) {
var s Server
@@ -5886,6 +5945,66 @@ func TestServerListenNotComparableListener(t *testing.T) {
s.Serve(make(eofListenerNotComparable, 1)) // used to panic
}
+// countCloseListener is a Listener wrapper that counts the number of Close calls.
+type countCloseListener struct {
+ net.Listener
+ closes int32 // atomic
+}
+
+func (p *countCloseListener) Close() error {
+ atomic.AddInt32(&p.closes, 1)
+ return nil
+}
+
+// Issue 24803: don't call Listener.Close on Server.Shutdown.
+func TestServerCloseListenerOnce(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ cl := &countCloseListener{Listener: ln}
+ server := &Server{}
+ sdone := make(chan bool, 1)
+
+ go func() {
+ server.Serve(cl)
+ sdone <- true
+ }()
+ time.Sleep(10 * time.Millisecond)
+ server.Shutdown(context.Background())
+ ln.Close()
+ <-sdone
+
+ nclose := atomic.LoadInt32(&cl.closes)
+ if nclose != 1 {
+ t.Errorf("Close calls = %v; want 1", nclose)
+ }
+}
+
+// Issue 23351: document and test behavior of ServeMux with ports
+func TestStripPortFromHost(t *testing.T) {
+ mux := NewServeMux()
+
+ mux.HandleFunc("example.com/", func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "OK")
+ })
+ mux.HandleFunc("example.com:9000/", func(w ResponseWriter, r *Request) {
+ fmt.Fprintf(w, "uh-oh!")
+ })
+
+ req := httptest.NewRequest("GET", "http://example.com:9000/", nil)
+ rw := httptest.NewRecorder()
+
+ mux.ServeHTTP(rw, req)
+
+ response := rw.Body.String()
+ if response != "OK" {
+ t.Errorf("Response gotten was %q", response)
+ }
+}
+
func BenchmarkResponseStatusLine(b *testing.B) {
b.ReportAllocs()
b.RunParallel(func(pb *testing.PB) {
diff --git a/src/net/http/server.go b/src/net/http/server.go
index 407546d6c9..5349c39c61 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -190,7 +190,9 @@ type Hijacker interface {
// data from the client.
//
// After a call to Hijack, the original Request.Body must not
- // be used, and the Request.Context will be canceled.
+ // be used. The original Request's Context remains valid and
+ // is not canceled until the Request's ServeHTTP method
+ // returns.
Hijack() (net.Conn, *bufio.ReadWriter, error)
}
@@ -281,7 +283,7 @@ type conn struct {
curReq atomic.Value // of *response (which has a Request in it)
- curState atomic.Value // of ConnState
+ curState struct{ atomic uint64 } // packed (unixtime<<8|uint8(ConnState))
// mu guards hijackedv
mu sync.Mutex
@@ -336,7 +338,7 @@ type chunkWriter struct {
res *response
// header is either nil or a deep clone of res.handlerHeader
- // at the time of res.WriteHeader, if res.WriteHeader is
+ // at the time of res.writeHeader, if res.writeHeader is
// called and extra buffering is being done to calculate
// Content-Type and/or Content-Length.
header Header
@@ -1677,21 +1679,19 @@ func (c *conn) setState(nc net.Conn, state ConnState) {
case StateHijacked, StateClosed:
srv.trackConn(c, false)
}
- c.curState.Store(connStateInterface[state])
+ if state > 0xff || state < 0 {
+ panic("internal error")
+ }
+ packedState := uint64(time.Now().Unix()<<8) | uint64(state)
+ atomic.StoreUint64(&c.curState.atomic, packedState)
if hook := srv.ConnState; hook != nil {
hook(nc, state)
}
}
-// connStateInterface is an array of the interface{} versions of
-// ConnState values, so we can use them in atomic.Values later without
-// paying the cost of shoving their integers in an interface{}.
-var connStateInterface = [...]interface{}{
- StateNew: StateNew,
- StateActive: StateActive,
- StateIdle: StateIdle,
- StateHijacked: StateHijacked,
- StateClosed: StateClosed,
+func (c *conn) getState() (state ConnState, unixSec int64) {
+ packedState := atomic.LoadUint64(&c.curState.atomic)
+ return ConnState(packedState & 0xff), int64(packedState >> 8)
}
// badRequestError is a literal string (used by in the server in HTML,
@@ -2135,9 +2135,9 @@ func RedirectHandler(url string, code int) Handler {
// "/codesearch" and "codesearch.google.com/" without also taking over
// requests for "http://www.google.com/".
//
-// ServeMux also takes care of sanitizing the URL request path,
-// redirecting any request containing . or .. elements or repeated slashes
-// to an equivalent, cleaner URL.
+// ServeMux also takes care of sanitizing the URL request path and the Host
+// header, stripping the port number and redirecting any request containing . or
+// .. elements or repeated slashes to an equivalent, cleaner URL.
type ServeMux struct {
mu sync.RWMutex
m map[string]muxEntry
@@ -2234,7 +2234,10 @@ func (mux *ServeMux) match(path string) (h Handler, pattern string) {
// not for path itself. If the path needs appending to, it creates a new
// URL, setting the path to u.Path + "/" and returning true to indicate so.
func (mux *ServeMux) redirectToPathSlash(host, path string, u *url.URL) (*url.URL, bool) {
- if !mux.shouldRedirect(host, path) {
+ mux.mu.RLock()
+ shouldRedirect := mux.shouldRedirectRLocked(host, path)
+ mux.mu.RUnlock()
+ if !shouldRedirect {
return u, false
}
path = path + "/"
@@ -2242,13 +2245,10 @@ func (mux *ServeMux) redirectToPathSlash(host, path string, u *url.URL) (*url.UR
return u, true
}
-// shouldRedirect reports whether the given path and host should be redirected to
+// shouldRedirectRLocked reports whether the given path and host should be redirected to
// path+"/". This should happen if a handler is registered for path+"/" but
// not path -- see comments at ServeMux.
-func (mux *ServeMux) shouldRedirect(host, path string) bool {
- mux.mu.RLock()
- defer mux.mu.RUnlock()
-
+func (mux *ServeMux) shouldRedirectRLocked(host, path string) bool {
p := []string{path, host + path}
for _, c := range p {
@@ -2622,8 +2622,16 @@ func (s *Server) closeIdleConns() bool {
defer s.mu.Unlock()
quiescent := true
for c := range s.activeConn {
- st, ok := c.curState.Load().(ConnState)
- if !ok || st != StateIdle {
+ st, unixSec := c.getState()
+ // Issue 22682: treat StateNew connections as if
+ // they're idle if we haven't read the first request's
+ // header in over 5 seconds.
+ if st == StateNew && unixSec < time.Now().Unix()-5 {
+ st = StateIdle
+ }
+ if st != StateIdle || unixSec == 0 {
+ // Assume unixSec == 0 means it's a very new
+ // connection, without state set yet.
quiescent = false
continue
}
@@ -2770,10 +2778,13 @@ var ErrServerClosed = errors.New("http: Server closed")
// Serve always returns a non-nil error. After Shutdown or Close, the
// returned error is ErrServerClosed.
func (srv *Server) Serve(l net.Listener) error {
- defer l.Close()
if fn := testHookServerServe; fn != nil {
- fn(srv, l)
+ fn(srv, l) // call hook with unwrapped listener
}
+
+ l = &onceCloseListener{Listener: l}
+ defer l.Close()
+
var tempDelay time.Duration // how long to sleep on accept failure
if err := srv.setupHTTP2_Serve(); err != nil {
@@ -3249,6 +3260,21 @@ func (ln tcpKeepAliveListener) Accept() (net.Conn, error) {
return tc, nil
}
+// onceCloseListener wraps a net.Listener, protecting it from
+// multiple Close calls.
+type onceCloseListener struct {
+ net.Listener
+ once sync.Once
+ closeErr error
+}
+
+func (oc *onceCloseListener) Close() error {
+ oc.once.Do(oc.close)
+ return oc.closeErr
+}
+
+func (oc *onceCloseListener) close() { oc.closeErr = oc.Listener.Close() }
+
// globalOptionsHandler responds to "OPTIONS *" requests.
type globalOptionsHandler struct{}
diff --git a/src/net/http/sniff.go b/src/net/http/sniff.go
index ff934ff357..c1494abb4c 100644
--- a/src/net/http/sniff.go
+++ b/src/net/http/sniff.go
@@ -147,6 +147,8 @@ var sniffSignatures = []sniffSig{
&exactSig{[]byte("\x50\x4B\x03\x04"), "application/zip"},
&exactSig{[]byte("\x1F\x8B\x08"), "application/x-gzip"},
+ &exactSig{[]byte("\x00\x61\x73\x6D"), "application/wasm"},
+
mp4Sig{},
textSig{}, // should be last
diff --git a/src/net/http/sniff_test.go b/src/net/http/sniff_test.go
index b9e9488610..b4d3c9f0cc 100644
--- a/src/net/http/sniff_test.go
+++ b/src/net/http/sniff_test.go
@@ -65,6 +65,7 @@ var sniffTests = []struct {
{"woff sample I", []byte("\x77\x4f\x46\x46\x00\x01\x00\x00\x00\x00\x30\x54\x00\x0d\x00\x00"), "font/woff"},
{"woff2 sample", []byte("\x77\x4f\x46\x32\x00\x01\x00\x00\x00"), "font/woff2"},
+ {"wasm sample", []byte("\x00\x61\x73\x6d\x01\x00"), "application/wasm"},
}
func TestDetectContentType(t *testing.T) {
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index c7171a0109..2c6ba3231b 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -11,6 +11,7 @@ import (
"fmt"
"io"
"io/ioutil"
+ "net/http/httptrace"
"net/http/internal"
"net/textproto"
"reflect"
@@ -280,11 +281,14 @@ func (t *transferWriter) shouldSendContentLength() bool {
return false
}
-func (t *transferWriter) WriteHeader(w io.Writer) error {
+func (t *transferWriter) writeHeader(w io.Writer, trace *httptrace.ClientTrace) error {
if t.Close && !hasToken(t.Header.get("Connection"), "close") {
if _, err := io.WriteString(w, "Connection: close\r\n"); err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("Connection", []string{"close"})
+ }
}
// Write Content-Length and/or Transfer-Encoding whose values are a
@@ -297,10 +301,16 @@ func (t *transferWriter) WriteHeader(w io.Writer) error {
if _, err := io.WriteString(w, strconv.FormatInt(t.ContentLength, 10)+"\r\n"); err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("Content-Length", []string{strconv.FormatInt(t.ContentLength, 10)})
+ }
} else if chunked(t.TransferEncoding) {
if _, err := io.WriteString(w, "Transfer-Encoding: chunked\r\n"); err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("Transfer-Encoding", []string{"chunked"})
+ }
}
// Write Trailer header
@@ -321,13 +331,16 @@ func (t *transferWriter) WriteHeader(w io.Writer) error {
if _, err := io.WriteString(w, "Trailer: "+strings.Join(keys, ",")+"\r\n"); err != nil {
return err
}
+ if trace != nil && trace.WroteHeaderField != nil {
+ trace.WroteHeaderField("Trailer", keys)
+ }
}
}
return nil
}
-func (t *transferWriter) WriteBody(w io.Writer) error {
+func (t *transferWriter) writeBody(w io.Writer) error {
var err error
var ncopy int64
diff --git a/src/net/http/transfer_test.go b/src/net/http/transfer_test.go
index 9a201aab2d..993ea4ef18 100644
--- a/src/net/http/transfer_test.go
+++ b/src/net/http/transfer_test.go
@@ -86,7 +86,7 @@ func TestDetectInMemoryReaders(t *testing.T) {
for i, tt := range tests {
got := isKnownInMemoryReader(tt.r)
if got != tt.want {
- t.Logf("%d: got = %v; want %v", i, got, tt.want)
+ t.Errorf("%d: got = %v; want %v", i, got, tt.want)
}
}
}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index 3890f19af3..a298e2ef03 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -21,6 +21,7 @@ import (
"log"
"net"
"net/http/httptrace"
+ "net/textproto"
"net/url"
"os"
"strings"
@@ -369,6 +370,13 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
}
for {
+ select {
+ case <-ctx.Done():
+ req.closeBody()
+ return nil, ctx.Err()
+ default:
+ }
+
// treq gets modified by roundTrip, so we need to recreate for each retry.
treq := &transportRequest{Request: req, trace: trace}
cm, err := t.connectMethodForRequest(treq)
@@ -1641,26 +1649,42 @@ func (pc *persistConn) readResponse(rc requestAndChan, trace *httptrace.ClientTr
trace.GotFirstResponseByte()
}
}
- resp, err = ReadResponse(pc.br, rc.req)
- if err != nil {
- return
- }
- if rc.continueCh != nil {
- if resp.StatusCode == 100 {
- if trace != nil && trace.Got100Continue != nil {
- trace.Got100Continue()
- }
- rc.continueCh <- struct{}{}
- } else {
- close(rc.continueCh)
- }
- }
- if resp.StatusCode == 100 {
- pc.readLimit = pc.maxHeaderResponseSize() // reset the limit
+ num1xx := 0 // number of informational 1xx headers received
+ const max1xxResponses = 5 // arbitrary bound on number of informational responses
+
+ continueCh := rc.continueCh
+ for {
resp, err = ReadResponse(pc.br, rc.req)
if err != nil {
return
}
+ resCode := resp.StatusCode
+ if continueCh != nil {
+ if resCode == 100 {
+ if trace != nil && trace.Got100Continue != nil {
+ trace.Got100Continue()
+ }
+ continueCh <- struct{}{}
+ continueCh = nil
+ } else if resCode >= 200 {
+ close(continueCh)
+ continueCh = nil
+ }
+ }
+ if 100 <= resCode && resCode <= 199 {
+ num1xx++
+ if num1xx > max1xxResponses {
+ return nil, errors.New("net/http: too many 1xx informational responses")
+ }
+ pc.readLimit = pc.maxHeaderResponseSize() // reset the limit
+ if trace != nil && trace.Got1xxResponse != nil {
+ if err := trace.Got1xxResponse(resCode, textproto.MIMEHeader(resp.Header)); err != nil {
+ return nil, err
+ }
+ }
+ continue
+ }
+ break
}
resp.TLS = pc.tlsState
return
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index 57309bbac1..979b8a9009 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -31,6 +31,7 @@ import (
"net/http/httptrace"
"net/http/httputil"
"net/http/internal"
+ "net/textproto"
"net/url"
"os"
"reflect"
@@ -2287,6 +2288,7 @@ Content-Length: %d
c := &Client{Transport: tr}
testResponse := func(req *Request, name string, wantCode int) {
+ t.Helper()
res, err := c.Do(req)
if err != nil {
t.Fatalf("%s: Do: %v", name, err)
@@ -2309,13 +2311,67 @@ Content-Length: %d
req.Header.Set("Request-Id", reqID(i))
testResponse(req, fmt.Sprintf("100, %d/%d", i, numReqs), 200)
}
+}
- // And some other informational 1xx but non-100 responses, to test
- // we return them but don't re-use the connection.
- for i := 1; i <= numReqs; i++ {
- req, _ := NewRequest("POST", "http://other.tld/", strings.NewReader(reqBody(i)))
- req.Header.Set("X-Want-Response-Code", "123 Sesame Street")
- testResponse(req, fmt.Sprintf("123, %d/%d", i, numReqs), 123)
+// Issue 17739: the HTTP client must ignore any unknown 1xx
+// informational responses before the actual response.
+func TestTransportIgnore1xxResponses(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ conn, buf, _ := w.(Hijacker).Hijack()
+ buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\nFoo: bar\r\n\r\nHTTP/1.1 200 OK\r\nBar: baz\r\nContent-Length: 5\r\n\r\nHello"))
+ buf.Flush()
+ conn.Close()
+ }))
+ defer cst.close()
+ cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway
+
+ var got bytes.Buffer
+
+ req, _ := NewRequest("GET", cst.ts.URL, nil)
+ req = req.WithContext(httptrace.WithClientTrace(context.Background(), &httptrace.ClientTrace{
+ Got1xxResponse: func(code int, header textproto.MIMEHeader) error {
+ fmt.Fprintf(&got, "1xx: code=%v, header=%v\n", code, header)
+ return nil
+ },
+ }))
+ res, err := cst.c.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+
+ res.Write(&got)
+ want := "1xx: code=123, header=map[Foo:[bar]]\nHTTP/1.1 200 OK\r\nContent-Length: 5\r\nBar: baz\r\n\r\nHello"
+ if got.String() != want {
+ t.Errorf(" got: %q\nwant: %q\n", got.Bytes(), want)
+ }
+}
+
+func TestTransportLimits1xxResponses(t *testing.T) {
+ setParallel(t)
+ defer afterTest(t)
+ cst := newClientServerTest(t, h1Mode, HandlerFunc(func(w ResponseWriter, r *Request) {
+ conn, buf, _ := w.(Hijacker).Hijack()
+ for i := 0; i < 10; i++ {
+ buf.Write([]byte("HTTP/1.1 123 OneTwoThree\r\n\r\n"))
+ }
+ buf.Write([]byte("HTTP/1.1 204 No Content\r\n\r\n"))
+ buf.Flush()
+ conn.Close()
+ }))
+ defer cst.close()
+ cst.tr.DisableKeepAlives = true // prevent log spam; our test server is hanging up anyway
+
+ res, err := cst.c.Get(cst.ts.URL)
+ if res != nil {
+ defer res.Body.Close()
+ }
+ got := fmt.Sprint(err)
+ wantSub := "too many 1xx informational responses"
+ if !strings.Contains(got, wantSub) {
+ t.Errorf("Get error = %v; want substring %q", err, wantSub)
}
}
@@ -3677,7 +3733,9 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
return []net.IPAddr{{IP: net.ParseIP(ip)}}, nil
})
- req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader("some body"))
+ body := "some body"
+ req, _ := NewRequest("POST", cst.scheme()+"://dns-is-faked.golang:"+port, strings.NewReader(body))
+ req.Header["X-Foo-Multiple-Vals"] = []string{"bar", "baz"}
trace := &httptrace.ClientTrace{
GetConn: func(hostPort string) { logf("Getting conn for %v ...", hostPort) },
GotConn: func(ci httptrace.GotConnInfo) { logf("got conn: %+v", ci) },
@@ -3692,6 +3750,12 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
}
logf("ConnectDone: connected to %s %s = %v", network, addr, err)
},
+ WroteHeaderField: func(key string, value []string) {
+ logf("WroteHeaderField: %s: %v", key, value)
+ },
+ WroteHeaders: func() {
+ logf("WroteHeaders")
+ },
Wait100Continue: func() { logf("Wait100Continue") },
Got100Continue: func() { logf("Got100Continue") },
WroteRequest: func(e httptrace.WroteRequestInfo) {
@@ -3761,7 +3825,15 @@ func testTransportEventTrace(t *testing.T, h2 bool, noHooks bool) {
wantOnce("tls handshake done")
} else {
wantOnce("PutIdleConn = <nil>")
- }
+ wantOnce("WroteHeaderField: User-Agent: [Go-http-client/1.1]")
+ // TODO(meirf): issue 19761. Make these agnostic to h1/h2. (These are not h1 specific, but the
+ // WroteHeaderField hook is not yet implemented in h2.)
+ wantOnce(fmt.Sprintf("WroteHeaderField: Host: [dns-is-faked.golang:%s]", port))
+ wantOnce(fmt.Sprintf("WroteHeaderField: Content-Length: [%d]", len(body)))
+ wantOnce("WroteHeaderField: X-Foo-Multiple-Vals: [bar baz]")
+ wantOnce("WroteHeaderField: Accept-Encoding: [gzip]")
+ }
+ wantOnce("WroteHeaders")
wantOnce("Wait100Continue")
wantOnce("Got100Continue")
wantOnce("WroteRequest: {Err:<nil>}")
@@ -4488,3 +4560,28 @@ func TestNoBodyOnChunked304Response(t *testing.T) {
type funcWriter func([]byte) (int, error)
func (f funcWriter) Write(p []byte) (int, error) { return f(p) }
+
+type doneContext struct {
+ context.Context
+ err error
+}
+
+func (doneContext) Done() <-chan struct{} {
+ c := make(chan struct{})
+ close(c)
+ return c
+}
+
+func (d doneContext) Err() error { return d.err }
+
+// Issue 25852: Transport should check whether Context is done early.
+func TestTransportCheckContextDoneEarly(t *testing.T) {
+ tr := &Transport{}
+ req, _ := NewRequest("GET", "http://fake.example/", nil)
+ wantErr := errors.New("some error")
+ req = req.WithContext(doneContext{context.Background(), wantErr})
+ _, err := tr.RoundTrip(req)
+ if err != wantErr {
+ t.Errorf("error = %v; want %v", err, wantErr)
+ }
+}
diff --git a/src/net/ip.go b/src/net/ip.go
index d5b4051794..da8dca588e 100644
--- a/src/net/ip.go
+++ b/src/net/ip.go
@@ -562,25 +562,26 @@ func parseIPv4(s string) IP {
return IPv4(p[0], p[1], p[2], p[3])
}
-// parseIPv6 parses s as a literal IPv6 address described in RFC 4291
-// and RFC 5952. It can also parse a literal scoped IPv6 address with
-// zone identifier which is described in RFC 4007 when zoneAllowed is
-// true.
-func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
+// parseIPv6Zone parses s as a literal IPv6 address and its associated zone
+// identifier which is described in RFC 4007.
+func parseIPv6Zone(s string) (IP, string) {
+ s, zone := splitHostZone(s)
+ return parseIPv6(s), zone
+}
+
+// parseIPv6Zone parses s as a literal IPv6 address described in RFC 4291
+// and RFC 5952.
+func parseIPv6(s string) (ip IP) {
ip = make(IP, IPv6len)
ellipsis := -1 // position of ellipsis in ip
- if zoneAllowed {
- s, zone = splitHostZone(s)
- }
-
// Might have leading ellipsis
if len(s) >= 2 && s[0] == ':' && s[1] == ':' {
ellipsis = 0
s = s[2:]
// Might be only ellipsis
if len(s) == 0 {
- return ip, zone
+ return ip
}
}
@@ -590,22 +591,22 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
// Hex number.
n, c, ok := xtoi(s)
if !ok || n > 0xFFFF {
- return nil, zone
+ return nil
}
// If followed by dot, might be in trailing IPv4.
if c < len(s) && s[c] == '.' {
if ellipsis < 0 && i != IPv6len-IPv4len {
// Not the right place.
- return nil, zone
+ return nil
}
if i+IPv4len > IPv6len {
// Not enough room.
- return nil, zone
+ return nil
}
ip4 := parseIPv4(s)
if ip4 == nil {
- return nil, zone
+ return nil
}
ip[i] = ip4[12]
ip[i+1] = ip4[13]
@@ -629,14 +630,14 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
// Otherwise must be followed by colon and more.
if s[0] != ':' || len(s) == 1 {
- return nil, zone
+ return nil
}
s = s[1:]
// Look for ellipsis.
if s[0] == ':' {
if ellipsis >= 0 { // already have one
- return nil, zone
+ return nil
}
ellipsis = i
s = s[1:]
@@ -648,13 +649,13 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
// Must have used entire string.
if len(s) != 0 {
- return nil, zone
+ return nil
}
// If didn't parse enough, expand ellipsis.
if i < IPv6len {
if ellipsis < 0 {
- return nil, zone
+ return nil
}
n := IPv6len - i
for j := i - 1; j >= ellipsis; j-- {
@@ -665,9 +666,9 @@ func parseIPv6(s string, zoneAllowed bool) (ip IP, zone string) {
}
} else if ellipsis >= 0 {
// Ellipsis must represent at least one 0 group.
- return nil, zone
+ return nil
}
- return ip, zone
+ return ip
}
// ParseIP parses s as an IP address, returning the result.
@@ -681,13 +682,26 @@ func ParseIP(s string) IP {
case '.':
return parseIPv4(s)
case ':':
- ip, _ := parseIPv6(s, false)
- return ip
+ return parseIPv6(s)
}
}
return nil
}
+// parseIPZone parses s as an IP address, return it and its associated zone
+// identifier (IPv6 only).
+func parseIPZone(s string) (IP, string) {
+ for i := 0; i < len(s); i++ {
+ switch s[i] {
+ case '.':
+ return parseIPv4(s), ""
+ case ':':
+ return parseIPv6Zone(s)
+ }
+ }
+ return nil, ""
+}
+
// ParseCIDR parses s as a CIDR notation IP address and prefix length,
// like "192.0.2.0/24" or "2001:db8::/32", as defined in
// RFC 4632 and RFC 4291.
@@ -706,7 +720,7 @@ func ParseCIDR(s string) (IP, *IPNet, error) {
ip := parseIPv4(addr)
if ip == nil {
iplen = IPv6len
- ip, _ = parseIPv6(addr, false)
+ ip = parseIPv6(addr)
}
n, i, ok := dtoi(mask)
if ip == nil || !ok || i != len(mask) || n < 0 || n > 8*iplen {
diff --git a/src/net/ipsock.go b/src/net/ipsock.go
index 947bdf3489..f4ff82bd75 100644
--- a/src/net/ipsock.go
+++ b/src/net/ipsock.go
@@ -276,24 +276,16 @@ func (r *Resolver) internetAddrList(ctx context.Context, net, addr string) (addr
}
// Try as a literal IP address, then as a DNS name.
- var ips []IPAddr
- if ip := parseIPv4(host); ip != nil {
- ips = []IPAddr{{IP: ip}}
- } else if ip, zone := parseIPv6(host, true); ip != nil {
- ips = []IPAddr{{IP: ip, Zone: zone}}
- // Issue 18806: if the machine has halfway configured
- // IPv6 such that it can bind on "::" (IPv6unspecified)
- // but not connect back to that same address, fall
- // back to dialing 0.0.0.0.
- if ip.Equal(IPv6unspecified) {
- ips = append(ips, IPAddr{IP: IPv4zero})
- }
- } else {
- // Try as a DNS name.
- ips, err = r.LookupIPAddr(ctx, host)
- if err != nil {
- return nil, err
- }
+ ips, err := r.LookupIPAddr(ctx, host)
+ if err != nil {
+ return nil, err
+ }
+ // Issue 18806: if the machine has halfway configured
+ // IPv6 such that it can bind on "::" (IPv6unspecified)
+ // but not connect back to that same address, fall
+ // back to dialing 0.0.0.0.
+ if len(ips) == 1 && ips[0].IP.Equal(IPv6unspecified) {
+ ips = append(ips, IPAddr{IP: IPv4zero})
}
var filter func(IPAddr) bool
diff --git a/src/net/lookup.go b/src/net/lookup.go
index 000f4a31ae..e0f21fa9a8 100644
--- a/src/net/lookup.go
+++ b/src/net/lookup.go
@@ -133,6 +133,11 @@ type Resolver struct {
// If nil, the default dialer is used.
Dial func(ctx context.Context, network, address string) (Conn, error)
+ // lookupGroup merges LookupIPAddr calls together for lookups for the same
+ // host. The lookupGroup key is the LookupIPAddr.host argument.
+ // The return values are ([]IPAddr, error).
+ lookupGroup singleflight.Group
+
// TODO(bradfitz): optional interface impl override hook
// TODO(bradfitz): Timeout time.Duration?
}
@@ -140,6 +145,13 @@ type Resolver struct {
func (r *Resolver) preferGo() bool { return r != nil && r.PreferGo }
func (r *Resolver) strictErrors() bool { return r != nil && r.StrictErrors }
+func (r *Resolver) getLookupGroup() *singleflight.Group {
+ if r == nil {
+ return &DefaultResolver.lookupGroup
+ }
+ return &r.lookupGroup
+}
+
// LookupHost looks up the given host using the local resolver.
// It returns a slice of that host's addresses.
func LookupHost(host string) (addrs []string, err error) {
@@ -150,11 +162,11 @@ func LookupHost(host string) (addrs []string, err error) {
// It returns a slice of that host's addresses.
func (r *Resolver) LookupHost(ctx context.Context, host string) (addrs []string, err error) {
// Make sure that no matter what we do later, host=="" is rejected.
- // ParseIP, for example, does accept empty strings.
+ // parseIP, for example, does accept empty strings.
if host == "" {
return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
}
- if ip := ParseIP(host); ip != nil {
+ if ip, _ := parseIPZone(host); ip != nil {
return []string{host}, nil
}
return r.lookupHost(ctx, host)
@@ -178,12 +190,12 @@ func LookupIP(host string) ([]IP, error) {
// It returns a slice of that host's IPv4 and IPv6 addresses.
func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, error) {
// Make sure that no matter what we do later, host=="" is rejected.
- // ParseIP, for example, does accept empty strings.
+ // parseIP, for example, does accept empty strings.
if host == "" {
return nil, &DNSError{Err: errNoSuchHost.Error(), Name: host}
}
- if ip := ParseIP(host); ip != nil {
- return []IPAddr{{IP: ip}}, nil
+ if ip, zone := parseIPZone(host); ip != nil {
+ return []IPAddr{{IP: ip, Zone: zone}}, nil
}
trace, _ := ctx.Value(nettrace.TraceKey{}).(*nettrace.Trace)
if trace != nil && trace.DNSStart != nil {
@@ -204,7 +216,7 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
lookupGroupCtx, lookupGroupCancel := context.WithCancel(context.Background())
dnsWaitGroup.Add(1)
- ch, called := lookupGroup.DoChan(host, func() (interface{}, error) {
+ ch, called := r.getLookupGroup().DoChan(host, func() (interface{}, error) {
defer dnsWaitGroup.Done()
return testHookLookupIP(lookupGroupCtx, resolverFunc, host)
})
@@ -221,7 +233,7 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
// let the lookup continue uncanceled, and let later
// lookups with the same key share the result.
// See issues 8602, 20703, 22724.
- if lookupGroup.ForgetUnshared(host) {
+ if r.getLookupGroup().ForgetUnshared(host) {
lookupGroupCancel()
} else {
go func() {
@@ -244,12 +256,6 @@ func (r *Resolver) LookupIPAddr(ctx context.Context, host string) ([]IPAddr, err
}
}
-// lookupGroup merges LookupIPAddr calls together for lookups
-// for the same host. The lookupGroup key is is the LookupIPAddr.host
-// argument.
-// The return values are ([]IPAddr, error).
-var lookupGroup singleflight.Group
-
// lookupIPReturn turns the return values from singleflight.Do into
// the return values from LookupIP.
func lookupIPReturn(addrsi interface{}, err error, shared bool) ([]IPAddr, error) {
diff --git a/src/net/lookup_fake.go b/src/net/lookup_fake.go
index 90c6d47183..d3d1dbc900 100644
--- a/src/net/lookup_fake.go
+++ b/src/net/lookup_fake.go
@@ -50,3 +50,9 @@ func (*Resolver) lookupTXT(ctx context.Context, name string) (txts []string, err
func (*Resolver) lookupAddr(ctx context.Context, addr string) (ptrs []string, err error) {
return nil, syscall.ENOPROTOOPT
}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups.
+func concurrentThreadsLimit() int {
+ return 500
+}
diff --git a/src/net/lookup_plan9.go b/src/net/lookup_plan9.go
index e0b38c69b9..5547f0b0ee 100644
--- a/src/net/lookup_plan9.go
+++ b/src/net/lookup_plan9.go
@@ -329,3 +329,9 @@ func (*Resolver) lookupAddr(ctx context.Context, addr string) (name []string, er
}
return
}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups.
+func concurrentThreadsLimit() int {
+ return 500
+}
diff --git a/src/net/lookup_test.go b/src/net/lookup_test.go
index 02fbcd8bac..5c66dfa260 100644
--- a/src/net/lookup_test.go
+++ b/src/net/lookup_test.go
@@ -15,6 +15,7 @@ import (
"runtime"
"sort"
"strings"
+ "sync"
"testing"
"time"
)
@@ -305,6 +306,32 @@ func TestLookupIPv6LinkLocalAddr(t *testing.T) {
}
}
+func TestLookupIPv6LinkLocalAddrWithZone(t *testing.T) {
+ if !supportsIPv6() || !*testIPv6 {
+ t.Skip("IPv6 is required")
+ }
+
+ ipaddrs, err := DefaultResolver.LookupIPAddr(context.Background(), "fe80::1%lo0")
+ if err != nil {
+ t.Error(err)
+ }
+ for _, addr := range ipaddrs {
+ if e, a := "lo0", addr.Zone; e != a {
+ t.Errorf("wrong zone: want %q, got %q", e, a)
+ }
+ }
+
+ addrs, err := DefaultResolver.LookupHost(context.Background(), "fe80::1%lo0")
+ if err != nil {
+ t.Error(err)
+ }
+ for _, addr := range addrs {
+ if e, a := "fe80::1%lo0", addr; e != a {
+ t.Errorf("wrong host: want %q got %q", e, a)
+ }
+ }
+}
+
var lookupCNAMETests = []struct {
name, cname string
}{
@@ -925,3 +952,59 @@ func TestLookupHostCancel(t *testing.T) {
t.Fatal(err)
}
}
+
+type lookupCustomResolver struct {
+ *Resolver
+ mu sync.RWMutex
+ dialed bool
+}
+
+func (lcr *lookupCustomResolver) dial() func(ctx context.Context, network, address string) (Conn, error) {
+ return func(ctx context.Context, network, address string) (Conn, error) {
+ lcr.mu.Lock()
+ lcr.dialed = true
+ lcr.mu.Unlock()
+ return Dial(network, address)
+ }
+}
+
+// TestConcurrentPreferGoResolversDial tests that multiple resolvers with the
+// PreferGo option used concurrently are all dialed properly.
+func TestConcurrentPreferGoResolversDial(t *testing.T) {
+ // The windows implementation of the resolver does not use the Dial
+ // function.
+ if runtime.GOOS == "windows" {
+ t.Skip("skip on windows")
+ }
+
+ testenv.MustHaveExternalNetwork(t)
+ testenv.SkipFlakyNet(t)
+
+ defer dnsWaitGroup.Wait()
+
+ resolvers := make([]*lookupCustomResolver, 2)
+ for i := range resolvers {
+ cs := lookupCustomResolver{Resolver: &Resolver{PreferGo: true}}
+ cs.Dial = cs.dial()
+ resolvers[i] = &cs
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(len(resolvers))
+ for i, resolver := range resolvers {
+ go func(r *Resolver, index int) {
+ defer wg.Done()
+ _, err := r.LookupIPAddr(context.Background(), "google.com")
+ if err != nil {
+ t.Fatalf("lookup failed for resolver %d: %q", index, err)
+ }
+ }(resolver.Resolver, i)
+ }
+ wg.Wait()
+
+ for i, resolver := range resolvers {
+ if !resolver.dialed {
+ t.Errorf("custom resolver %d not dialed during lookup", i)
+ }
+ }
+}
diff --git a/src/net/lookup_unix.go b/src/net/lookup_unix.go
index 0cf4c99e0c..2c3191aca8 100644
--- a/src/net/lookup_unix.go
+++ b/src/net/lookup_unix.go
@@ -9,6 +9,7 @@ package net
import (
"context"
"sync"
+ "syscall"
"golang_org/x/net/dns/dnsmessage"
)
@@ -315,3 +316,27 @@ func (r *Resolver) lookupAddr(ctx context.Context, addr string) ([]string, error
}
return r.goLookupPTR(ctx, addr)
}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups via cgo. A DNS lookup may use a
+// file descriptor so we limit this to less than the number of
+// permitted open files. On some systems, notably Darwin, if
+// getaddrinfo is unable to open a file descriptor it simply returns
+// EAI_NONAME rather than a useful error. Limiting the number of
+// concurrent getaddrinfo calls to less than the permitted number of
+// file descriptors makes that error less likely. We don't bother to
+// apply the same limit to DNS lookups run directly from Go, because
+// there we will return a meaningful "too many open files" error.
+func concurrentThreadsLimit() int {
+ var rlim syscall.Rlimit
+ if err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rlim); err != nil {
+ return 500
+ }
+ r := int(rlim.Cur)
+ if r > 500 {
+ r = 500
+ } else if r > 30 {
+ r -= 30
+ }
+ return r
+}
diff --git a/src/net/lookup_windows.go b/src/net/lookup_windows.go
index e1a811ce39..f76e0af400 100644
--- a/src/net/lookup_windows.go
+++ b/src/net/lookup_windows.go
@@ -364,3 +364,9 @@ Cname:
}
return name
}
+
+// concurrentThreadsLimit returns the number of threads we permit to
+// run concurrently doing DNS lookups.
+func concurrentThreadsLimit() int {
+ return 500
+}
diff --git a/src/net/net.go b/src/net/net.go
index 48c5001670..c909986269 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -84,6 +84,7 @@ import (
"internal/poll"
"io"
"os"
+ "sync"
"syscall"
"time"
)
@@ -610,9 +611,14 @@ func genericReadFrom(w io.Writer, r io.Reader) (n int64, err error) {
// server is not responding. Then the many lookups each use a different
// thread, and the system or the program runs out of threads.
-var threadLimit = make(chan struct{}, 500)
+var threadLimit chan struct{}
+
+var threadOnce sync.Once
func acquireThread() {
+ threadOnce.Do(func() {
+ threadLimit = make(chan struct{}, concurrentThreadsLimit())
+ })
threadLimit <- struct{}{}
}
diff --git a/src/net/net_fake.go b/src/net/net_fake.go
index f7595d9bb4..0c48dd5c03 100644
--- a/src/net/net_fake.go
+++ b/src/net/net_fake.go
@@ -50,7 +50,7 @@ type netFD struct {
// unused
pfd poll.FD
- isConnected bool
+ isConnected bool // handshake completed or use of association with peer
}
// socket returns a network file descriptor that is ready for
diff --git a/src/net/sendfile_test.go b/src/net/sendfile_test.go
index 75d4b4e9bf..ecc00d3c2a 100644
--- a/src/net/sendfile_test.go
+++ b/src/net/sendfile_test.go
@@ -7,6 +7,7 @@
package net
import (
+ "bytes"
"crypto/sha256"
"encoding/hex"
"fmt"
@@ -90,3 +91,61 @@ func TestSendfile(t *testing.T) {
t.Error(err)
}
}
+
+func TestSendfileParts(t *testing.T) {
+ ln, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer ln.Close()
+
+ errc := make(chan error, 1)
+ go func(ln Listener) {
+ // Wait for a connection.
+ conn, err := ln.Accept()
+ if err != nil {
+ errc <- err
+ close(errc)
+ return
+ }
+
+ go func() {
+ defer close(errc)
+ defer conn.Close()
+
+ f, err := os.Open(twain)
+ if err != nil {
+ errc <- err
+ return
+ }
+ defer f.Close()
+
+ for i := 0; i < 3; i++ {
+ // Return file data using io.CopyN, which should use
+ // sendFile if available.
+ _, err = io.CopyN(conn, f, 3)
+ if err != nil {
+ errc <- err
+ return
+ }
+ }
+ }()
+ }(ln)
+
+ c, err := Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer c.Close()
+
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(c)
+
+ if want, have := "Produced ", buf.String(); have != want {
+ t.Errorf("unexpected server reply %q, want %q", have, want)
+ }
+
+ for err := range errc {
+ t.Error(err)
+ }
+}
diff --git a/src/net/sendfile_unix_alt.go b/src/net/sendfile_unix_alt.go
index 97aeebbed2..9b3ba4ee62 100644
--- a/src/net/sendfile_unix_alt.go
+++ b/src/net/sendfile_unix_alt.go
@@ -63,5 +63,11 @@ func sendFile(c *netFD, r io.Reader) (written int64, err error, handled bool) {
if lr != nil {
lr.N = remain - written
}
+
+ _, err1 := f.Seek(written, io.SeekCurrent)
+ if err1 != nil && err == nil {
+ return written, err1, written > 0
+ }
+
return written, wrapSyscallError("sendfile", err), written > 0
}
diff --git a/src/net/splice_test.go b/src/net/splice_test.go
index 483a9e555f..2f1e69ddb6 100644
--- a/src/net/splice_test.go
+++ b/src/net/splice_test.go
@@ -10,6 +10,8 @@ import (
"bytes"
"fmt"
"io"
+ "io/ioutil"
+ "sync"
"testing"
)
@@ -19,6 +21,7 @@ func TestSplice(t *testing.T) {
t.Run("big", testSpliceBig)
t.Run("honorsLimitedReader", testSpliceHonorsLimitedReader)
t.Run("readerAtEOF", testSpliceReaderAtEOF)
+ t.Run("issue25985", testSpliceIssue25985)
}
func testSpliceSimple(t *testing.T) {
@@ -234,6 +237,66 @@ func testSpliceReaderAtEOF(t *testing.T) {
}
}
+func testSpliceIssue25985(t *testing.T) {
+ front, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer front.Close()
+ back, err := newLocalListener("tcp")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer back.Close()
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ proxy := func() {
+ src, err := front.Accept()
+ if err != nil {
+ return
+ }
+ dst, err := Dial("tcp", back.Addr().String())
+ if err != nil {
+ return
+ }
+ defer dst.Close()
+ defer src.Close()
+ go func() {
+ io.Copy(src, dst)
+ wg.Done()
+ }()
+ go func() {
+ io.Copy(dst, src)
+ wg.Done()
+ }()
+ }
+
+ go proxy()
+
+ toFront, err := Dial("tcp", front.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ io.WriteString(toFront, "foo")
+ toFront.Close()
+
+ fromProxy, err := back.Accept()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer fromProxy.Close()
+
+ _, err = ioutil.ReadAll(fromProxy)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ wg.Wait()
+}
+
func BenchmarkTCPReadFrom(b *testing.B) {
testHookUninstaller.Do(uninstallTestHooks)
diff --git a/src/os/fifo_test.go b/src/os/fifo_test.go
new file mode 100644
index 0000000000..3041dcfa02
--- /dev/null
+++ b/src/os/fifo_test.go
@@ -0,0 +1,112 @@
+// Copyright 2015 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 darwin dragonfly freebsd linux netbsd openbsd
+
+package os_test
+
+import (
+ "bufio"
+ "bytes"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "runtime"
+ "sync"
+ "syscall"
+ "testing"
+ "time"
+)
+
+// Issue 24164.
+func TestFifoEOF(t *testing.T) {
+ switch runtime.GOOS {
+ case "android":
+ t.Skip("skipping on Android; mkfifo syscall not available")
+ case "openbsd":
+ // On OpenBSD 6.2 this test just hangs for some reason.
+ t.Skip("skipping on OpenBSD; issue 25877")
+ }
+
+ dir, err := ioutil.TempDir("", "TestFifoEOF")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ fifoName := filepath.Join(dir, "fifo")
+ if err := syscall.Mkfifo(fifoName, 0600); err != nil {
+ t.Fatal(err)
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ w, err := os.OpenFile(fifoName, os.O_WRONLY, 0)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ defer func() {
+ if err := w.Close(); err != nil {
+ t.Errorf("error closing writer: %v", err)
+ }
+ }()
+
+ for i := 0; i < 3; i++ {
+ time.Sleep(10 * time.Millisecond)
+ _, err := fmt.Fprintf(w, "line %d\n", i)
+ if err != nil {
+ t.Errorf("error writing to fifo: %v", err)
+ return
+ }
+ }
+ time.Sleep(10 * time.Millisecond)
+ }()
+
+ defer wg.Wait()
+
+ r, err := os.Open(fifoName)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ done := make(chan bool)
+ go func() {
+ defer close(done)
+
+ defer func() {
+ if err := r.Close(); err != nil {
+ t.Errorf("error closing reader: %v", err)
+ }
+ }()
+
+ rbuf := bufio.NewReader(r)
+ for {
+ b, err := rbuf.ReadBytes('\n')
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ t.Logf("%s\n", bytes.TrimSpace(b))
+ }
+ }()
+
+ select {
+ case <-done:
+ // Test succeeded.
+ case <-time.After(time.Second):
+ t.Error("timed out waiting for read")
+ // Close the reader to force the read to complete.
+ r.Close()
+ }
+}
diff --git a/src/os/file.go b/src/os/file.go
index fa73919620..cba70d78fb 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -342,25 +342,28 @@ func TempDir() string {
// On Plan 9, it returns $home/lib/cache.
//
// If the location cannot be determined (for example, $HOME is not defined),
-// then it will return an empty string.
-func UserCacheDir() string {
+// then it will return an error.
+func UserCacheDir() (string, error) {
var dir string
switch runtime.GOOS {
case "windows":
dir = Getenv("LocalAppData")
+ if dir == "" {
+ return "", errors.New("%LocalAppData% is not defined")
+ }
case "darwin":
dir = Getenv("HOME")
if dir == "" {
- return ""
+ return "", errors.New("$HOME is not defined")
}
dir += "/Library/Caches"
case "plan9":
dir = Getenv("home")
if dir == "" {
- return ""
+ return "", errors.New("$home is not defined")
}
dir += "/lib/cache"
@@ -369,13 +372,13 @@ func UserCacheDir() string {
if dir == "" {
dir = Getenv("HOME")
if dir == "" {
- return ""
+ return "", errors.New("neither $XDG_CACHE_HOME nor $HOME are defined")
}
dir += "/.cache"
}
}
- return dir
+ return dir, nil
}
// Chmod changes the mode of the named file to mode.
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index 11fdb19808..e0b8119d96 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -114,6 +114,8 @@ func newFile(fd uintptr, name string, kind newFileKind) *File {
stdoutOrErr: fdi == 1 || fdi == 2,
}}
+ pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
+
// Don't try to use kqueue with regular files on FreeBSD.
// It crashes the system unpredictably while running all.bash.
// Issue 19093.
@@ -121,10 +123,19 @@ func newFile(fd uintptr, name string, kind newFileKind) *File {
// we assume they know what they are doing so we allow it to be
// used with kqueue.
if runtime.GOOS == "freebsd" && kind == kindOpenFile {
- kind = kindNewFile
+ pollable = false
+ }
+
+ // On Darwin, kqueue does not work properly with fifos:
+ // closing the last writer does not cause a kqueue event
+ // for any readers. See issue #24164.
+ if runtime.GOOS == "darwin" && kind == kindOpenFile {
+ var st syscall.Stat_t
+ if err := syscall.Fstat(fdi, &st); err == nil && st.Mode&syscall.S_IFMT == syscall.S_IFIFO {
+ pollable = false
+ }
}
- pollable := kind == kindOpenFile || kind == kindPipe || kind == kindNonBlock
if err := f.pfd.Init("file", pollable); err != nil {
// An error here indicates a failure to register
// with the netpoll system. That can happen for
diff --git a/src/os/path.go b/src/os/path.go
index 5c5350670d..cdfbc18921 100644
--- a/src/os/path.go
+++ b/src/os/path.go
@@ -6,7 +6,6 @@ package os
import (
"io"
- "runtime"
"syscall"
)
@@ -84,32 +83,35 @@ func RemoveAll(path string) error {
return err
}
- // Directory.
- fd, err := Open(path)
- if err != nil {
- if IsNotExist(err) {
- // Race. It was deleted between the Lstat and Open.
- // Return nil per RemoveAll's docs.
- return nil
- }
- return err
- }
-
// Remove contents & return first error.
err = nil
for {
- if err == nil && (runtime.GOOS == "plan9" || runtime.GOOS == "nacl") {
- // Reset read offset after removing directory entries.
- // See golang.org/issue/22572.
- fd.Seek(0, 0)
+ fd, err := Open(path)
+ if err != nil {
+ if IsNotExist(err) {
+ // Already deleted by someone else.
+ return nil
+ }
+ return err
}
- names, err1 := fd.Readdirnames(100)
+
+ const request = 1024
+ names, err1 := fd.Readdirnames(request)
+
+ // Removing files from the directory may have caused
+ // the OS to reshuffle it. Simply calling Readdirnames
+ // again may skip some entries. The only reliable way
+ // to avoid this is to close and re-open the
+ // directory. See issue 20841.
+ fd.Close()
+
for _, name := range names {
err1 := RemoveAll(path + string(PathSeparator) + name)
if err == nil {
err = err1
}
}
+
if err1 == io.EOF {
break
}
@@ -120,10 +122,29 @@ func RemoveAll(path string) error {
if len(names) == 0 {
break
}
- }
- // Close directory, because windows won't remove opened directory.
- fd.Close()
+ // We don't want to re-open unnecessarily, so if we
+ // got fewer than request names from Readdirnames, try
+ // simply removing the directory now. If that
+ // succeeds, we are done.
+ if len(names) < request {
+ err1 := Remove(path)
+ if err1 == nil || IsNotExist(err1) {
+ return nil
+ }
+
+ if err != nil {
+ // We got some error removing the
+ // directory contents, and since we
+ // read fewer names than we requested
+ // there probably aren't more files to
+ // remove. Don't loop around to read
+ // the directory again. We'll probably
+ // just get the same error.
+ return err
+ }
+ }
+ }
// Remove directory.
err1 := Remove(path)
diff --git a/src/os/pipe_test.go b/src/os/pipe_test.go
index 929e9bec53..a6d955a8e4 100644
--- a/src/os/pipe_test.go
+++ b/src/os/pipe_test.go
@@ -8,6 +8,8 @@
package os_test
import (
+ "bufio"
+ "bytes"
"fmt"
"internal/testenv"
"io"
@@ -305,3 +307,91 @@ func testCloseWithBlockingRead(t *testing.T, r, w *os.File) {
wg.Wait()
}
+
+// Issue 24164, for pipes.
+func TestPipeEOF(t *testing.T) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var wg sync.WaitGroup
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+
+ defer func() {
+ if err := w.Close(); err != nil {
+ t.Errorf("error closing writer: %v", err)
+ }
+ }()
+
+ for i := 0; i < 3; i++ {
+ time.Sleep(10 * time.Millisecond)
+ _, err := fmt.Fprintf(w, "line %d\n", i)
+ if err != nil {
+ t.Errorf("error writing to fifo: %v", err)
+ return
+ }
+ }
+ time.Sleep(10 * time.Millisecond)
+ }()
+
+ defer wg.Wait()
+
+ done := make(chan bool)
+ go func() {
+ defer close(done)
+
+ defer func() {
+ if err := r.Close(); err != nil {
+ t.Errorf("error closing reader: %v", err)
+ }
+ }()
+
+ rbuf := bufio.NewReader(r)
+ for {
+ b, err := rbuf.ReadBytes('\n')
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ t.Logf("%s\n", bytes.TrimSpace(b))
+ }
+ }()
+
+ select {
+ case <-done:
+ // Test succeeded.
+ case <-time.After(time.Second):
+ t.Error("timed out waiting for read")
+ // Close the reader to force the read to complete.
+ r.Close()
+ }
+}
+
+// Issue 24481.
+func TestFdRace(t *testing.T) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer r.Close()
+ defer w.Close()
+
+ var wg sync.WaitGroup
+ call := func() {
+ defer wg.Done()
+ w.Fd()
+ }
+
+ const tries = 100
+ for i := 0; i < tries; i++ {
+ wg.Add(1)
+ go call()
+ }
+ wg.Wait()
+}
diff --git a/src/race.bash b/src/race.bash
index cafd834777..73cb1e583b 100755
--- a/src/race.bash
+++ b/src/race.bash
@@ -9,7 +9,7 @@
set -e
function usage {
- echo 'race detector is only supported on linux/amd64, freebsd/amd64 and darwin/amd64' 1>&2
+ echo 'race detector is only supported on linux/amd64, linux/ppc64le, freebsd/amd64 and darwin/amd64' 1>&2
exit 1
}
@@ -21,7 +21,7 @@ case $(uname) in
fi
;;
"Linux")
- if [ $(uname -m) != "x86_64" ]; then
+ if [ $(uname -m) != "x86_64" ] && [ $(uname -m) != "ppc64le" ]; then
usage
fi
;;
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index 63d068cd78..cf7fe3cf7a 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -4817,13 +4817,29 @@ func (i StructI) Get() int { return int(i) }
type StructIPtr int
-func (i *StructIPtr) Get() int { return int(*i) }
+func (i *StructIPtr) Get() int { return int(*i) }
+func (i *StructIPtr) Set(v int) { *(*int)(i) = v }
+
+type SettableStruct struct {
+ SettableField int
+}
+
+func (p *SettableStruct) Set(v int) { p.SettableField = v }
+
+type SettablePointer struct {
+ SettableField *int
+}
+
+func (p *SettablePointer) Set(v int) { *p.SettableField = v }
func TestStructOfWithInterface(t *testing.T) {
const want = 42
type Iface interface {
Get() int
}
+ type IfaceSet interface {
+ Set(int)
+ }
tests := []struct {
name string
typ Type
@@ -4931,6 +4947,76 @@ func TestStructOfWithInterface(t *testing.T) {
}
}
}
+
+ // Test an embedded nil pointer with pointer methods.
+ fields := []StructField{{
+ Name: "StructIPtr",
+ Anonymous: true,
+ Type: PtrTo(TypeOf(StructIPtr(want))),
+ }}
+ rt := StructOf(fields)
+ rv := New(rt).Elem()
+ // This should panic since the pointer is nil.
+ shouldPanic(func() {
+ rv.Interface().(IfaceSet).Set(want)
+ })
+
+ // Test an embedded nil pointer to a struct with pointer methods.
+
+ fields = []StructField{{
+ Name: "SettableStruct",
+ Anonymous: true,
+ Type: PtrTo(TypeOf(SettableStruct{})),
+ }}
+ rt = StructOf(fields)
+ rv = New(rt).Elem()
+ // This should panic since the pointer is nil.
+ shouldPanic(func() {
+ rv.Interface().(IfaceSet).Set(want)
+ })
+
+ // The behavior is different if there is a second field,
+ // since now an interface value holds a pointer to the struct
+ // rather than just holding a copy of the struct.
+ fields = []StructField{
+ {
+ Name: "SettableStruct",
+ Anonymous: true,
+ Type: PtrTo(TypeOf(SettableStruct{})),
+ },
+ {
+ Name: "EmptyStruct",
+ Anonymous: true,
+ Type: StructOf(nil),
+ },
+ }
+ // With the current implementation this is expected to panic.
+ // Ideally it should work and we should be able to see a panic
+ // if we call the Set method.
+ shouldPanic(func() {
+ StructOf(fields)
+ })
+
+ // Embed a field that can be stored directly in an interface,
+ // with a second field.
+ fields = []StructField{
+ {
+ Name: "SettablePointer",
+ Anonymous: true,
+ Type: TypeOf(SettablePointer{}),
+ },
+ {
+ Name: "EmptyStruct",
+ Anonymous: true,
+ Type: StructOf(nil),
+ },
+ }
+ // With the current implementation this is expected to panic.
+ // Ideally it should work and we should be able to call the
+ // Set and Get methods.
+ shouldPanic(func() {
+ StructOf(fields)
+ })
}
func TestChanOf(t *testing.T) {
diff --git a/src/reflect/type.go b/src/reflect/type.go
index 1f3b665ce4..58cfc0e884 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -290,9 +290,7 @@ const (
)
// rtype is the common implementation of most values.
-// It is embedded in other, public struct types, but always
-// with a unique tag like `reflect:"array"` or `reflect:"ptr"`
-// so that code cannot convert from, say, *arrayType to *ptrType.
+// It is embedded in other struct types.
//
// rtype must be kept in sync with ../runtime/type.go:/^type._type.
type rtype struct {
@@ -350,7 +348,7 @@ const (
// arrayType represents a fixed array type.
type arrayType struct {
- rtype `reflect:"array"`
+ rtype
elem *rtype // array element type
slice *rtype // slice type
len uintptr
@@ -358,9 +356,9 @@ type arrayType struct {
// chanType represents a channel type.
type chanType struct {
- rtype `reflect:"chan"`
- elem *rtype // channel element type
- dir uintptr // channel direction (ChanDir)
+ rtype
+ elem *rtype // channel element type
+ dir uintptr // channel direction (ChanDir)
}
// funcType represents a function type.
@@ -375,7 +373,7 @@ type chanType struct {
// [2]*rtype // [0] is in, [1] is out
// }
type funcType struct {
- rtype `reflect:"func"`
+ rtype
inCount uint16
outCount uint16 // top bit is set if last input parameter is ...
}
@@ -388,14 +386,14 @@ type imethod struct {
// interfaceType represents an interface type.
type interfaceType struct {
- rtype `reflect:"interface"`
+ rtype
pkgPath name // import path
methods []imethod // sorted by hash
}
// mapType represents a map type.
type mapType struct {
- rtype `reflect:"map"`
+ rtype
key *rtype // map key type
elem *rtype // map element (value) type
bucket *rtype // internal bucket structure
@@ -410,14 +408,14 @@ type mapType struct {
// ptrType represents a pointer type.
type ptrType struct {
- rtype `reflect:"ptr"`
- elem *rtype // pointer element (pointed at) type
+ rtype
+ elem *rtype // pointer element (pointed at) type
}
// sliceType represents a slice type.
type sliceType struct {
- rtype `reflect:"slice"`
- elem *rtype // slice element type
+ rtype
+ elem *rtype // slice element type
}
// Struct field
@@ -437,7 +435,7 @@ func (f *structField) embedded() bool {
// structType represents a struct type.
type structType struct {
- rtype `reflect:"struct"`
+ rtype
pkgPath name
fields []structField // sorted by offset
}
@@ -2467,6 +2465,9 @@ func StructOf(fields []StructField) Type {
// Issue 15924.
panic("reflect: embedded type with methods not implemented if type is not first field")
}
+ if len(fields) > 1 {
+ panic("reflect: embedded type with methods not implemented if there is more than one field")
+ }
for _, m := range unt.methods() {
mname := ptr.nameOff(m.name)
if mname.pkgPath() != "" {
@@ -2504,6 +2505,9 @@ func StructOf(fields []StructField) Type {
// Issue 15924.
panic("reflect: embedded type with methods not implemented if type is not first field")
}
+ if len(fields) > 1 && ft.kind&kindDirectIface != 0 {
+ panic("reflect: embedded type with methods not implemented for non-pointer type")
+ }
for _, m := range unt.methods() {
mname := ft.nameOff(m.name)
if mname.pkgPath() != "" {
diff --git a/src/regexp/example_test.go b/src/regexp/example_test.go
index 0bf1f6bee7..eb8cd4ea94 100644
--- a/src/regexp/example_test.go
+++ b/src/regexp/example_test.go
@@ -38,6 +38,12 @@ func ExampleMatchString() {
// false error parsing regexp: missing closing ): `a(b`
}
+func ExampleQuoteMeta() {
+ fmt.Println(regexp.QuoteMeta("Escaping symbols like: .+*?()|[]{}^$"))
+ // Output:
+ // Escaping symbols like: \.\+\*\?\(\)\|\[\]\{\}\^\$
+}
+
func ExampleRegexp_FindString() {
re := regexp.MustCompile("foo.?")
fmt.Printf("%q\n", re.FindString("seafood fool"))
diff --git a/src/regexp/regexp.go b/src/regexp/regexp.go
index 09faced8f3..0d10aa1e22 100644
--- a/src/regexp/regexp.go
+++ b/src/regexp/regexp.go
@@ -616,9 +616,9 @@ func init() {
}
}
-// QuoteMeta returns a string that quotes all regular expression metacharacters
+// QuoteMeta returns a string that escapes all regular expression metacharacters
// inside the argument text; the returned string is a regular expression matching
-// the literal text. For example, QuoteMeta(`[foo]`) returns `\[foo\]`.
+// the literal text.
func QuoteMeta(s string) string {
// A byte loop is correct because all metacharacters are ASCII.
var i int
diff --git a/src/runtime/asm_arm.s b/src/runtime/asm_arm.s
index 545e58e9b0..6722ba760f 100644
--- a/src/runtime/asm_arm.s
+++ b/src/runtime/asm_arm.s
@@ -36,25 +36,28 @@ TEXT _rt0_arm_lib(SB),NOSPLIT,$104
MOVW R6, 20(R13)
MOVW R7, 24(R13)
MOVW R8, 28(R13)
- MOVW R11, 32(R13)
+ MOVW g, 32(R13)
+ MOVW R11, 36(R13)
// Skip floating point registers on GOARM < 6.
MOVB runtime·goarm(SB), R11
CMP $6, R11
BLT skipfpsave
- MOVD F8, (32+8*1)(R13)
- MOVD F9, (32+8*2)(R13)
- MOVD F10, (32+8*3)(R13)
- MOVD F11, (32+8*4)(R13)
- MOVD F12, (32+8*5)(R13)
- MOVD F13, (32+8*6)(R13)
- MOVD F14, (32+8*7)(R13)
- MOVD F15, (32+8*8)(R13)
+ MOVD F8, (40+8*0)(R13)
+ MOVD F9, (40+8*1)(R13)
+ MOVD F10, (40+8*2)(R13)
+ MOVD F11, (40+8*3)(R13)
+ MOVD F12, (40+8*4)(R13)
+ MOVD F13, (40+8*5)(R13)
+ MOVD F14, (40+8*6)(R13)
+ MOVD F15, (40+8*7)(R13)
skipfpsave:
// Save argc/argv.
MOVW R0, _rt0_arm_lib_argc<>(SB)
MOVW R1, _rt0_arm_lib_argv<>(SB)
+ MOVW $0, g // Initialize g.
+
// Synchronous initialization.
CALL runtime·libpreinit(SB)
@@ -77,21 +80,22 @@ rr:
MOVB runtime·goarm(SB), R11
CMP $6, R11
BLT skipfprest
- MOVD (32+8*1)(R13), F8
- MOVD (32+8*2)(R13), F9
- MOVD (32+8*3)(R13), F10
- MOVD (32+8*4)(R13), F11
- MOVD (32+8*5)(R13), F12
- MOVD (32+8*6)(R13), F13
- MOVD (32+8*7)(R13), F14
- MOVD (32+8*8)(R13), F15
+ MOVD (40+8*0)(R13), F8
+ MOVD (40+8*1)(R13), F9
+ MOVD (40+8*2)(R13), F10
+ MOVD (40+8*3)(R13), F11
+ MOVD (40+8*4)(R13), F12
+ MOVD (40+8*5)(R13), F13
+ MOVD (40+8*6)(R13), F14
+ MOVD (40+8*7)(R13), F15
skipfprest:
MOVW 12(R13), R4
MOVW 16(R13), R5
MOVW 20(R13), R6
MOVW 24(R13), R7
MOVW 28(R13), R8
- MOVW 32(R13), R11
+ MOVW 32(R13), g
+ MOVW 36(R13), R11
RET
// _rt0_arm_lib_go initializes the Go runtime.
@@ -582,6 +586,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
MOVW arg+4(FP), R0
MOVW R13, R2
+ CMP $0, g
+ BEQ nosave
MOVW g, R4
// Figure out if we need to switch to m->g0 stack.
@@ -590,10 +596,10 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
MOVW g_m(g), R8
MOVW m_gsignal(R8), R3
CMP R3, g
- BEQ noswitch
+ BEQ nosave
MOVW m_g0(R8), R3
CMP R3, g
- BEQ noswitch
+ BEQ nosave
BL gosave<>(SB)
MOVW R0, R5
MOVW R3, R0
@@ -602,7 +608,6 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-12
MOVW (g_sched+gobuf_sp)(g), R13
// Now on a scheduling stack (a pthread-created stack).
-noswitch:
SUB $24, R13
BIC $0x7, R13 // alignment for gcc ABI
MOVW R4, 20(R13) // save old g
@@ -624,6 +629,30 @@ noswitch:
MOVW R0, ret+8(FP)
RET
+nosave:
+ // Running on a system stack, perhaps even without a g.
+ // Having no g can happen during thread creation or thread teardown
+ // (see needm/dropm on Solaris, for example).
+ // This code is like the above sequence but without saving/restoring g
+ // and without worrying about the stack moving out from under us
+ // (because we're on a system stack, not a goroutine stack).
+ // The above code could be used directly if already on a system stack,
+ // but then the only path through this code would be a rare case on Solaris.
+ // Using this code for all "already on system stack" calls exercises it more,
+ // which should help keep it correct.
+ SUB $24, R13
+ BIC $0x7, R13 // alignment for gcc ABI
+ // save null g in case someone looks during debugging.
+ MOVW $0, R4
+ MOVW R4, 20(R13)
+ MOVW R2, 16(R13) // Save old stack pointer.
+ BL (R1)
+ // Restore stack pointer.
+ MOVW 16(R13), R2
+ MOVW R2, R13
+ MOVW R0, ret+8(FP)
+ RET
+
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
// Turn the fn into a Go func (by taking its address) and call
// cgocallback_gofunc.
diff --git a/src/runtime/asm_arm64.s b/src/runtime/asm_arm64.s
index d1b90b056c..af389be9fe 100644
--- a/src/runtime/asm_arm64.s
+++ b/src/runtime/asm_arm64.s
@@ -863,6 +863,8 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
MOVD arg+8(FP), R0
MOVD RSP, R2 // save original stack pointer
+ CMP $0, g
+ BEQ nosave
MOVD g, R4
// Figure out if we need to switch to m->g0 stack.
@@ -871,10 +873,12 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
MOVD g_m(g), R8
MOVD m_gsignal(R8), R3
CMP R3, g
- BEQ noswitch
+ BEQ nosave
MOVD m_g0(R8), R3
CMP R3, g
- BEQ noswitch
+ BEQ nosave
+
+ // Switch to system stack.
MOVD R0, R9 // gosave<> and save_g might clobber R0
BL gosave<>(SB)
MOVD R3, g
@@ -884,12 +888,10 @@ TEXT ·asmcgocall(SB),NOSPLIT,$0-20
MOVD R9, R0
// Now on a scheduling stack (a pthread-created stack).
-noswitch:
// Save room for two of our pointers /*, plus 32 bytes of callee
// save area that lives on the caller stack. */
MOVD RSP, R13
SUB $16, R13
- BIC $0xf, R13 // alignment for gcc ABI
MOVD R13, RSP
MOVD R4, 0(RSP) // save old g on stack
MOVD (g_stack+stack_hi)(R4), R4
@@ -910,6 +912,30 @@ noswitch:
MOVW R0, ret+16(FP)
RET
+nosave:
+ // Running on a system stack, perhaps even without a g.
+ // Having no g can happen during thread creation or thread teardown
+ // (see needm/dropm on Solaris, for example).
+ // This code is like the above sequence but without saving/restoring g
+ // and without worrying about the stack moving out from under us
+ // (because we're on a system stack, not a goroutine stack).
+ // The above code could be used directly if already on a system stack,
+ // but then the only path through this code would be a rare case on Solaris.
+ // Using this code for all "already on system stack" calls exercises it more,
+ // which should help keep it correct.
+ MOVD RSP, R13
+ SUB $16, R13
+ MOVD R13, RSP
+ MOVD $0, R4
+ MOVD R4, 0(RSP) // Where above code stores g, in case someone looks during debugging.
+ MOVD R2, 8(RSP) // Save original stack pointer.
+ BL (R1)
+ // Restore stack pointer.
+ MOVD 8(RSP), R2
+ MOVD R2, RSP
+ MOVD R0, ret+16(FP)
+ RET
+
// cgocallback(void (*fn)(void*), void *frame, uintptr framesize, uintptr ctxt)
// Turn the fn into a Go func (by taking its address) and call
// cgocallback_gofunc.
diff --git a/src/runtime/asm_ppc64x.s b/src/runtime/asm_ppc64x.s
index 93f9110cc0..0886de9f2b 100644
--- a/src/runtime/asm_ppc64x.s
+++ b/src/runtime/asm_ppc64x.s
@@ -24,6 +24,7 @@ TEXT runtime·rt0_go(SB),NOSPLIT,$0
// create istack out of the given (operating system) stack.
// _cgo_init may update stackguard.
MOVD $runtime·g0(SB), g
+ BL runtime·save_g(SB)
MOVD $(-64*1024), R31
ADD R31, R1, R3
MOVD R3, g_stackguard0(g)
@@ -139,6 +140,7 @@ TEXT runtime·gogo(SB), NOSPLIT, $16-8
MOVD 0(g), R4
MOVD gobuf_sp(R5), R1
MOVD gobuf_lr(R5), R31
+ MOVD 24(R1), R2 // restore R2
MOVD R31, LR
MOVD gobuf_ret(R5), R3
MOVD gobuf_ctxt(R5), R11
@@ -455,7 +457,19 @@ CALLFN(·call268435456, 268435456)
CALLFN(·call536870912, 536870912)
CALLFN(·call1073741824, 1073741824)
-TEXT runtime·procyield(SB),NOSPLIT,$0-0
+TEXT runtime·procyield(SB),NOSPLIT|NOFRAME,$0-4
+ MOVW cycles+0(FP), R7
+ // POWER does not have a pause/yield instruction equivalent.
+ // Instead, we can lower the program priority by setting the
+ // Program Priority Register prior to the wait loop and set it
+ // back to default afterwards. On Linux, the default priority is
+ // medium-low. For details, see page 837 of the ISA 3.0.
+ OR R1, R1, R1 // Set PPR priority to low
+again:
+ SUB $1, R7
+ CMP $0, R7
+ BNE again
+ OR R6, R6, R6 // Set PPR priority back to medium-low
RET
// void jmpdefer(fv, sp);
diff --git a/src/runtime/asm_wasm.s b/src/runtime/asm_wasm.s
index 67d7bf17dd..baf840d0cf 100644
--- a/src/runtime/asm_wasm.s
+++ b/src/runtime/asm_wasm.s
@@ -186,7 +186,7 @@ TEXT runtime·return0(SB), NOSPLIT, $0-0
RET
TEXT runtime·jmpdefer(SB), NOSPLIT, $0-16
- MOVD fn+0(FP), CTXT
+ MOVD fv+0(FP), CTXT
Get CTXT
I64Eqz
@@ -297,7 +297,7 @@ TEXT reflect·call(SB), NOSPLIT, $0-0
JMP ·reflectcall(SB)
TEXT ·reflectcall(SB), NOSPLIT, $0-32
- I64Load f+8(FP)
+ I64Load fn+8(FP)
I64Eqz
If
CALLNORESUME runtime·sigpanic(SB)
diff --git a/src/runtime/defs_darwin.go b/src/runtime/defs_darwin.go
index e3a25c5312..d5dc7944ee 100644
--- a/src/runtime/defs_darwin.go
+++ b/src/runtime/defs_darwin.go
@@ -15,8 +15,6 @@ package runtime
/*
#define __DARWIN_UNIX03 0
-#include <mach/mach.h>
-#include <mach/message.h>
#include <mach/mach_time.h>
#include <sys/types.h>
#include <sys/time.h>
@@ -25,12 +23,14 @@ package runtime
#include <sys/event.h>
#include <sys/mman.h>
#include <pthread.h>
+#include <fcntl.h>
*/
import "C"
const (
- EINTR = C.EINTR
- EFAULT = C.EFAULT
+ EINTR = C.EINTR
+ EFAULT = C.EFAULT
+ ETIMEDOUT = C.ETIMEDOUT
PROT_NONE = C.PROT_NONE
PROT_READ = C.PROT_READ
@@ -44,40 +44,6 @@ const (
MADV_DONTNEED = C.MADV_DONTNEED
MADV_FREE = C.MADV_FREE
- MACH_MSG_TYPE_MOVE_RECEIVE = C.MACH_MSG_TYPE_MOVE_RECEIVE
- MACH_MSG_TYPE_MOVE_SEND = C.MACH_MSG_TYPE_MOVE_SEND
- MACH_MSG_TYPE_MOVE_SEND_ONCE = C.MACH_MSG_TYPE_MOVE_SEND_ONCE
- MACH_MSG_TYPE_COPY_SEND = C.MACH_MSG_TYPE_COPY_SEND
- MACH_MSG_TYPE_MAKE_SEND = C.MACH_MSG_TYPE_MAKE_SEND
- MACH_MSG_TYPE_MAKE_SEND_ONCE = C.MACH_MSG_TYPE_MAKE_SEND_ONCE
- MACH_MSG_TYPE_COPY_RECEIVE = C.MACH_MSG_TYPE_COPY_RECEIVE
-
- MACH_MSG_PORT_DESCRIPTOR = C.MACH_MSG_PORT_DESCRIPTOR
- MACH_MSG_OOL_DESCRIPTOR = C.MACH_MSG_OOL_DESCRIPTOR
- MACH_MSG_OOL_PORTS_DESCRIPTOR = C.MACH_MSG_OOL_PORTS_DESCRIPTOR
- MACH_MSG_OOL_VOLATILE_DESCRIPTOR = C.MACH_MSG_OOL_VOLATILE_DESCRIPTOR
-
- MACH_MSGH_BITS_COMPLEX = C.MACH_MSGH_BITS_COMPLEX
-
- MACH_SEND_MSG = C.MACH_SEND_MSG
- MACH_RCV_MSG = C.MACH_RCV_MSG
- MACH_RCV_LARGE = C.MACH_RCV_LARGE
-
- MACH_SEND_TIMEOUT = C.MACH_SEND_TIMEOUT
- MACH_SEND_INTERRUPT = C.MACH_SEND_INTERRUPT
- MACH_SEND_ALWAYS = C.MACH_SEND_ALWAYS
- MACH_SEND_TRAILER = C.MACH_SEND_TRAILER
- MACH_RCV_TIMEOUT = C.MACH_RCV_TIMEOUT
- MACH_RCV_NOTIFY = C.MACH_RCV_NOTIFY
- MACH_RCV_INTERRUPT = C.MACH_RCV_INTERRUPT
- MACH_RCV_OVERWRITE = C.MACH_RCV_OVERWRITE
-
- NDR_PROTOCOL_2_0 = C.NDR_PROTOCOL_2_0
- NDR_INT_BIG_ENDIAN = C.NDR_INT_BIG_ENDIAN
- NDR_INT_LITTLE_ENDIAN = C.NDR_INT_LITTLE_ENDIAN
- NDR_FLOAT_IEEE = C.NDR_FLOAT_IEEE
- NDR_CHAR_ASCII = C.NDR_CHAR_ASCII
-
SA_SIGINFO = C.SA_SIGINFO
SA_RESTART = C.SA_RESTART
SA_ONSTACK = C.SA_ONSTACK
@@ -146,18 +112,17 @@ const (
EVFILT_WRITE = C.EVFILT_WRITE
PTHREAD_CREATE_DETACHED = C.PTHREAD_CREATE_DETACHED
-)
-type MachBody C.mach_msg_body_t
-type MachHeader C.mach_msg_header_t
-type MachNDR C.NDR_record_t
-type MachPort C.mach_msg_port_descriptor_t
+ F_SETFD = C.F_SETFD
+ FD_CLOEXEC = C.FD_CLOEXEC
+)
type StackT C.struct_sigaltstack
type Sighandler C.union___sigaction_u
type Sigaction C.struct___sigaction // used in syscalls
type Usigaction C.struct_sigaction // used by sigaction second argument
+type Sigset C.sigset_t
type Sigval C.union_sigval
type Siginfo C.siginfo_t
type Timeval C.struct_timeval
@@ -185,5 +150,9 @@ type Kevent C.struct_kevent
type Pthread C.pthread_t
type PthreadAttr C.pthread_attr_t
+type PthreadMutex C.pthread_mutex_t
+type PthreadMutexAttr C.pthread_mutexattr_t
+type PthreadCond C.pthread_cond_t
+type PthreadCondAttr C.pthread_condattr_t
type MachTimebaseInfo C.mach_timebase_info_data_t
diff --git a/src/runtime/defs_darwin_386.go b/src/runtime/defs_darwin_386.go
index 7f8ae9c934..24a6f15ca7 100644
--- a/src/runtime/defs_darwin_386.go
+++ b/src/runtime/defs_darwin_386.go
@@ -6,8 +6,9 @@ package runtime
import "unsafe"
const (
- _EINTR = 0x4
- _EFAULT = 0xe
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _ETIMEDOUT = 0x3c
_PROT_NONE = 0x0
_PROT_READ = 0x1
@@ -21,40 +22,6 @@ const (
_MADV_DONTNEED = 0x4
_MADV_FREE = 0x5
- _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
- _MACH_MSG_TYPE_MOVE_SEND = 0x11
- _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
- _MACH_MSG_TYPE_COPY_SEND = 0x13
- _MACH_MSG_TYPE_MAKE_SEND = 0x14
- _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
- _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
-
- _MACH_MSG_PORT_DESCRIPTOR = 0x0
- _MACH_MSG_OOL_DESCRIPTOR = 0x1
- _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
- _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
-
- _MACH_MSGH_BITS_COMPLEX = 0x80000000
-
- _MACH_SEND_MSG = 0x1
- _MACH_RCV_MSG = 0x2
- _MACH_RCV_LARGE = 0x4
-
- _MACH_SEND_TIMEOUT = 0x10
- _MACH_SEND_INTERRUPT = 0x40
- _MACH_SEND_ALWAYS = 0x10000
- _MACH_SEND_TRAILER = 0x20000
- _MACH_RCV_TIMEOUT = 0x100
- _MACH_RCV_NOTIFY = 0x200
- _MACH_RCV_INTERRUPT = 0x400
- _MACH_RCV_OVERWRITE = 0x1000
-
- _NDR_PROTOCOL_2_0 = 0x0
- _NDR_INT_BIG_ENDIAN = 0x0
- _NDR_INT_LITTLE_ENDIAN = 0x1
- _NDR_FLOAT_IEEE = 0x0
- _NDR_CHAR_ASCII = 0x0
-
_SA_SIGINFO = 0x40
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
@@ -123,39 +90,10 @@ const (
_EVFILT_WRITE = -0x2
_PTHREAD_CREATE_DETACHED = 0x2
-)
-
-type machbody struct {
- msgh_descriptor_count uint32
-}
-
-type machheader struct {
- msgh_bits uint32
- msgh_size uint32
- msgh_remote_port uint32
- msgh_local_port uint32
- msgh_reserved uint32
- msgh_id int32
-}
-
-type machndr struct {
- mig_vers uint8
- if_vers uint8
- reserved1 uint8
- mig_encoding uint8
- int_rep uint8
- char_rep uint8
- float_rep uint8
- reserved2 uint8
-}
-type machport struct {
- name uint32
- pad1 uint32
- pad2 uint16
- disposition uint8
- _type uint8
-}
+ _F_SETFD = 0x2
+ _FD_CLOEXEC = 0x1
+)
type stackt struct {
ss_sp *byte
@@ -208,6 +146,12 @@ type timespec struct {
tv_nsec int32
}
+//go:nosplit
+func (t *timespec) set_nsec(ns int64) {
+ t.tv_sec = int32(ns / 1000000000)
+ t.tv_nsec = int32(ns % 1000000000)
+}
+
type fpcontrol struct {
pad_cgo_0 [2]byte
}
@@ -395,6 +339,22 @@ type pthreadattr struct {
X__sig int32
X__opaque [36]int8
}
+type pthreadmutex struct {
+ X__sig int32
+ X__opaque [40]int8
+}
+type pthreadmutexattr struct {
+ X__sig int32
+ X__opaque [8]int8
+}
+type pthreadcond struct {
+ X__sig int32
+ X__opaque [24]int8
+}
+type pthreadcondattr struct {
+ X__sig int32
+ X__opaque [4]int8
+}
type machTimebaseInfo struct {
numer uint32
denom uint32
diff --git a/src/runtime/defs_darwin_amd64.go b/src/runtime/defs_darwin_amd64.go
index f35b90a5fa..dc4faeb770 100644
--- a/src/runtime/defs_darwin_amd64.go
+++ b/src/runtime/defs_darwin_amd64.go
@@ -6,8 +6,9 @@ package runtime
import "unsafe"
const (
- _EINTR = 0x4
- _EFAULT = 0xe
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _ETIMEDOUT = 0x3c
_PROT_NONE = 0x0
_PROT_READ = 0x1
@@ -21,40 +22,6 @@ const (
_MADV_DONTNEED = 0x4
_MADV_FREE = 0x5
- _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
- _MACH_MSG_TYPE_MOVE_SEND = 0x11
- _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
- _MACH_MSG_TYPE_COPY_SEND = 0x13
- _MACH_MSG_TYPE_MAKE_SEND = 0x14
- _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
- _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
-
- _MACH_MSG_PORT_DESCRIPTOR = 0x0
- _MACH_MSG_OOL_DESCRIPTOR = 0x1
- _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
- _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
-
- _MACH_MSGH_BITS_COMPLEX = 0x80000000
-
- _MACH_SEND_MSG = 0x1
- _MACH_RCV_MSG = 0x2
- _MACH_RCV_LARGE = 0x4
-
- _MACH_SEND_TIMEOUT = 0x10
- _MACH_SEND_INTERRUPT = 0x40
- _MACH_SEND_ALWAYS = 0x10000
- _MACH_SEND_TRAILER = 0x20000
- _MACH_RCV_TIMEOUT = 0x100
- _MACH_RCV_NOTIFY = 0x200
- _MACH_RCV_INTERRUPT = 0x400
- _MACH_RCV_OVERWRITE = 0x1000
-
- _NDR_PROTOCOL_2_0 = 0x0
- _NDR_INT_BIG_ENDIAN = 0x0
- _NDR_INT_LITTLE_ENDIAN = 0x1
- _NDR_FLOAT_IEEE = 0x0
- _NDR_CHAR_ASCII = 0x0
-
_SA_SIGINFO = 0x40
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
@@ -123,39 +90,10 @@ const (
_EVFILT_WRITE = -0x2
_PTHREAD_CREATE_DETACHED = 0x2
-)
-
-type machbody struct {
- msgh_descriptor_count uint32
-}
-
-type machheader struct {
- msgh_bits uint32
- msgh_size uint32
- msgh_remote_port uint32
- msgh_local_port uint32
- msgh_reserved uint32
- msgh_id int32
-}
-type machndr struct {
- mig_vers uint8
- if_vers uint8
- reserved1 uint8
- mig_encoding uint8
- int_rep uint8
- char_rep uint8
- float_rep uint8
- reserved2 uint8
-}
-
-type machport struct {
- name uint32
- pad1 uint32
- pad2 uint16
- disposition uint8
- _type uint8
-}
+ _F_SETFD = 0x2
+ _FD_CLOEXEC = 0x1
+)
type stackt struct {
ss_sp *byte
@@ -210,6 +148,12 @@ type timespec struct {
tv_nsec int64
}
+//go:nosplit
+func (t *timespec) set_nsec(ns int64) {
+ t.tv_sec = ns / 1000000000
+ t.tv_nsec = ns % 1000000000
+}
+
type fpcontrol struct {
pad_cgo_0 [2]byte
}
@@ -398,6 +342,23 @@ type pthreadattr struct {
X__sig int64
X__opaque [56]int8
}
+type pthreadmutex struct {
+ X__sig int64
+ X__opaque [56]int8
+}
+type pthreadmutexattr struct {
+ X__sig int64
+ X__opaque [8]int8
+}
+type pthreadcond struct {
+ X__sig int64
+ X__opaque [40]int8
+}
+type pthreadcondattr struct {
+ X__sig int64
+ X__opaque [8]int8
+}
+
type machTimebaseInfo struct {
numer uint32
denom uint32
diff --git a/src/runtime/defs_darwin_arm.go b/src/runtime/defs_darwin_arm.go
index 39a65bca01..52dfbd04b7 100644
--- a/src/runtime/defs_darwin_arm.go
+++ b/src/runtime/defs_darwin_arm.go
@@ -8,8 +8,9 @@ package runtime
import "unsafe"
const (
- _EINTR = 0x4
- _EFAULT = 0xe
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _ETIMEDOUT = 0x3c
_PROT_NONE = 0x0
_PROT_READ = 0x1
@@ -23,40 +24,6 @@ const (
_MADV_DONTNEED = 0x4
_MADV_FREE = 0x5
- _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
- _MACH_MSG_TYPE_MOVE_SEND = 0x11
- _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
- _MACH_MSG_TYPE_COPY_SEND = 0x13
- _MACH_MSG_TYPE_MAKE_SEND = 0x14
- _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
- _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
-
- _MACH_MSG_PORT_DESCRIPTOR = 0x0
- _MACH_MSG_OOL_DESCRIPTOR = 0x1
- _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
- _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
-
- _MACH_MSGH_BITS_COMPLEX = 0x80000000
-
- _MACH_SEND_MSG = 0x1
- _MACH_RCV_MSG = 0x2
- _MACH_RCV_LARGE = 0x4
-
- _MACH_SEND_TIMEOUT = 0x10
- _MACH_SEND_INTERRUPT = 0x40
- _MACH_SEND_ALWAYS = 0x10000
- _MACH_SEND_TRAILER = 0x20000
- _MACH_RCV_TIMEOUT = 0x100
- _MACH_RCV_NOTIFY = 0x200
- _MACH_RCV_INTERRUPT = 0x400
- _MACH_RCV_OVERWRITE = 0x1000
-
- _NDR_PROTOCOL_2_0 = 0x0
- _NDR_INT_BIG_ENDIAN = 0x0
- _NDR_INT_LITTLE_ENDIAN = 0x1
- _NDR_FLOAT_IEEE = 0x0
- _NDR_CHAR_ASCII = 0x0
-
_SA_SIGINFO = 0x40
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
@@ -125,39 +92,10 @@ const (
_EVFILT_WRITE = -0x2
_PTHREAD_CREATE_DETACHED = 0x2
-)
-
-type machbody struct {
- msgh_descriptor_count uint32
-}
-
-type machheader struct {
- msgh_bits uint32
- msgh_size uint32
- msgh_remote_port uint32
- msgh_local_port uint32
- msgh_reserved uint32
- msgh_id int32
-}
-
-type machndr struct {
- mig_vers uint8
- if_vers uint8
- reserved1 uint8
- mig_encoding uint8
- int_rep uint8
- char_rep uint8
- float_rep uint8
- reserved2 uint8
-}
-type machport struct {
- name uint32
- pad1 uint32
- pad2 uint16
- disposition uint8
- _type uint8
-}
+ _F_SETFD = 0x2
+ _FD_CLOEXEC = 0x1
+)
type stackt struct {
ss_sp *byte
@@ -210,6 +148,12 @@ type timespec struct {
tv_nsec int32
}
+//go:nosplit
+func (t *timespec) set_nsec(ns int64) {
+ t.tv_sec = int32(ns / 1000000000)
+ t.tv_nsec = int32(ns % 1000000000)
+}
+
type floatstate32 struct {
r [32]uint32
fpscr uint32
@@ -258,6 +202,22 @@ type pthreadattr struct {
X__sig int32
X__opaque [36]int8
}
+type pthreadmutex struct {
+ X__sig int32
+ X__opaque [40]int8
+}
+type pthreadmutexattr struct {
+ X__sig int32
+ X__opaque [8]int8
+}
+type pthreadcond struct {
+ X__sig int32
+ X__opaque [24]int8
+}
+type pthreadcondattr struct {
+ X__sig int32
+ X__opaque [4]int8
+}
type machTimebaseInfo struct {
numer uint32
diff --git a/src/runtime/defs_darwin_arm64.go b/src/runtime/defs_darwin_arm64.go
index 607051ff88..fb5acaca3d 100644
--- a/src/runtime/defs_darwin_arm64.go
+++ b/src/runtime/defs_darwin_arm64.go
@@ -6,8 +6,9 @@ package runtime
import "unsafe"
const (
- _EINTR = 0x4
- _EFAULT = 0xe
+ _EINTR = 0x4
+ _EFAULT = 0xe
+ _ETIMEDOUT = 0x3c
_PROT_NONE = 0x0
_PROT_READ = 0x1
@@ -21,40 +22,6 @@ const (
_MADV_DONTNEED = 0x4
_MADV_FREE = 0x5
- _MACH_MSG_TYPE_MOVE_RECEIVE = 0x10
- _MACH_MSG_TYPE_MOVE_SEND = 0x11
- _MACH_MSG_TYPE_MOVE_SEND_ONCE = 0x12
- _MACH_MSG_TYPE_COPY_SEND = 0x13
- _MACH_MSG_TYPE_MAKE_SEND = 0x14
- _MACH_MSG_TYPE_MAKE_SEND_ONCE = 0x15
- _MACH_MSG_TYPE_COPY_RECEIVE = 0x16
-
- _MACH_MSG_PORT_DESCRIPTOR = 0x0
- _MACH_MSG_OOL_DESCRIPTOR = 0x1
- _MACH_MSG_OOL_PORTS_DESCRIPTOR = 0x2
- _MACH_MSG_OOL_VOLATILE_DESCRIPTOR = 0x3
-
- _MACH_MSGH_BITS_COMPLEX = 0x80000000
-
- _MACH_SEND_MSG = 0x1
- _MACH_RCV_MSG = 0x2
- _MACH_RCV_LARGE = 0x4
-
- _MACH_SEND_TIMEOUT = 0x10
- _MACH_SEND_INTERRUPT = 0x40
- _MACH_SEND_ALWAYS = 0x10000
- _MACH_SEND_TRAILER = 0x20000
- _MACH_RCV_TIMEOUT = 0x100
- _MACH_RCV_NOTIFY = 0x200
- _MACH_RCV_INTERRUPT = 0x400
- _MACH_RCV_OVERWRITE = 0x1000
-
- _NDR_PROTOCOL_2_0 = 0x0
- _NDR_INT_BIG_ENDIAN = 0x0
- _NDR_INT_LITTLE_ENDIAN = 0x1
- _NDR_FLOAT_IEEE = 0x0
- _NDR_CHAR_ASCII = 0x0
-
_SA_SIGINFO = 0x40
_SA_RESTART = 0x2
_SA_ONSTACK = 0x1
@@ -123,39 +90,10 @@ const (
_EVFILT_WRITE = -0x2
_PTHREAD_CREATE_DETACHED = 0x2
-)
-
-type machbody struct {
- msgh_descriptor_count uint32
-}
-
-type machheader struct {
- msgh_bits uint32
- msgh_size uint32
- msgh_remote_port uint32
- msgh_local_port uint32
- msgh_reserved uint32
- msgh_id int32
-}
-type machndr struct {
- mig_vers uint8
- if_vers uint8
- reserved1 uint8
- mig_encoding uint8
- int_rep uint8
- char_rep uint8
- float_rep uint8
- reserved2 uint8
-}
-
-type machport struct {
- name uint32
- pad1 uint32
- pad2 uint16
- disposition uint8
- _type uint8
-}
+ _F_SETFD = 0x2
+ _FD_CLOEXEC = 0x1
+)
type stackt struct {
ss_sp *byte
@@ -210,6 +148,12 @@ type timespec struct {
tv_nsec int64
}
+//go:nosplit
+func (t *timespec) set_nsec(ns int64) {
+ t.tv_sec = ns / 1000000000
+ t.tv_nsec = ns % 1000000000
+}
+
type exceptionstate64 struct {
far uint64 // virtual fault addr
esr uint32 // exception syndrome
@@ -261,6 +205,22 @@ type pthreadattr struct {
X__sig int64
X__opaque [56]int8
}
+type pthreadmutex struct {
+ X__sig int64
+ X__opaque [56]int8
+}
+type pthreadmutexattr struct {
+ X__sig int64
+ X__opaque [8]int8
+}
+type pthreadcond struct {
+ X__sig int64
+ X__opaque [40]int8
+}
+type pthreadcondattr struct {
+ X__sig int64
+ X__opaque [8]int8
+}
type machTimebaseInfo struct {
numer uint32
diff --git a/src/runtime/iface.go b/src/runtime/iface.go
index 4362f2cd5b..15c412c4e6 100644
--- a/src/runtime/iface.go
+++ b/src/runtime/iface.go
@@ -18,7 +18,7 @@ var (
itabTableInit = itabTableType{size: itabInitSize} // starter table
)
-//Note: change the formula in the mallocgc call in itabAdd if you change these fields.
+// Note: change the formula in the mallocgc call in itabAdd if you change these fields.
type itabTableType struct {
size uintptr // length of entries array. Always a power of 2.
count uintptr // current number of filled entries.
diff --git a/src/runtime/internal/atomic/bench_test.go b/src/runtime/internal/atomic/bench_test.go
index 2a22e88fb8..083a75cb07 100644
--- a/src/runtime/internal/atomic/bench_test.go
+++ b/src/runtime/internal/atomic/bench_test.go
@@ -42,3 +42,23 @@ func BenchmarkAtomicStore(b *testing.B) {
atomic.Store(&x, 0)
}
}
+
+func BenchmarkXadd(b *testing.B) {
+ var x uint32
+ ptr := &x
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ atomic.Xadd(ptr, 1)
+ }
+ })
+}
+
+func BenchmarkXadd64(b *testing.B) {
+ var x uint64
+ ptr := &x
+ b.RunParallel(func(pb *testing.PB) {
+ for pb.Next() {
+ atomic.Xadd64(ptr, 1)
+ }
+ })
+}
diff --git a/src/runtime/internal/sys/arch.go b/src/runtime/internal/sys/arch.go
index d9debaeef7..75beb7872f 100644
--- a/src/runtime/internal/sys/arch.go
+++ b/src/runtime/internal/sys/arch.go
@@ -15,5 +15,5 @@ const (
MIPS64
PPC64
S390X
- Wasm
+ WASM
)
diff --git a/src/runtime/internal/sys/arch_wasm.go b/src/runtime/internal/sys/arch_wasm.go
index 54fcd1e92e..5463f934d6 100644
--- a/src/runtime/internal/sys/arch_wasm.go
+++ b/src/runtime/internal/sys/arch_wasm.go
@@ -5,7 +5,7 @@
package sys
const (
- ArchFamily = Wasm
+ ArchFamily = WASM
BigEndian = false
CacheLineSize = 64
DefaultPhysPageSize = 65536
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index 18dd4629a0..b590c4b92b 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -229,3 +229,9 @@ func notetsleepg(n *note, ns int64) bool {
exitsyscall()
return ok
}
+
+func pauseSchedulerUntilCallback() bool {
+ return false
+}
+
+func checkTimeouts() {}
diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go
index 21e53d075e..df321e5196 100644
--- a/src/runtime/lock_js.go
+++ b/src/runtime/lock_js.go
@@ -6,14 +6,22 @@
package runtime
+import (
+ _ "unsafe"
+)
+
// js/wasm has no support for threads yet. There is no preemption.
-// Waiting for a mutex or timeout is implemented as a busy loop
-// while allowing other goroutines to run.
+// Waiting for a mutex is implemented by allowing other goroutines
+// to run until the mutex gets unlocked.
const (
mutex_unlocked = 0
mutex_locked = 1
+ note_cleared = 0
+ note_woken = 1
+ note_timeout = 2
+
active_spin = 4
active_spin_cnt = 30
passive_spin = 1
@@ -21,7 +29,7 @@ const (
func lock(l *mutex) {
for l.key == mutex_locked {
- Gosched()
+ mcall(gosched_m)
}
l.key = mutex_locked
}
@@ -34,16 +42,31 @@ func unlock(l *mutex) {
}
// One-time notifications.
+
+type noteWithTimeout struct {
+ gp *g
+ deadline int64
+}
+
+var (
+ notes = make(map[*note]*g)
+ notesWithTimeout = make(map[*note]noteWithTimeout)
+)
+
func noteclear(n *note) {
- n.key = 0
+ n.key = note_cleared
}
func notewakeup(n *note) {
- if n.key != 0 {
- print("notewakeup - double wakeup (", n.key, ")\n")
+ // gp := getg()
+ if n.key == note_woken {
throw("notewakeup - double wakeup")
}
- n.key = 1
+ cleared := n.key == note_cleared
+ n.key = note_woken
+ if cleared {
+ goready(notes[n], 1)
+ }
}
func notesleep(n *note) {
@@ -62,14 +85,88 @@ func notetsleepg(n *note, ns int64) bool {
throw("notetsleepg on g0")
}
- deadline := nanotime() + ns
- for {
- if n.key != 0 {
- return true
+ if ns >= 0 {
+ deadline := nanotime() + ns
+ delay := ns/1000000 + 1 // round up
+ if delay > 1<<31-1 {
+ delay = 1<<31 - 1 // cap to max int32
}
- Gosched()
- if ns >= 0 && nanotime() >= deadline {
- return false
+
+ id := scheduleCallback(delay)
+ mp := acquirem()
+ notes[n] = gp
+ notesWithTimeout[n] = noteWithTimeout{gp: gp, deadline: deadline}
+ releasem(mp)
+
+ gopark(nil, nil, waitReasonSleep, traceEvNone, 1)
+
+ clearScheduledCallback(id) // note might have woken early, clear timeout
+ mp = acquirem()
+ delete(notes, n)
+ delete(notesWithTimeout, n)
+ releasem(mp)
+
+ return n.key == note_woken
+ }
+
+ for n.key != note_woken {
+ mp := acquirem()
+ notes[n] = gp
+ releasem(mp)
+
+ gopark(nil, nil, waitReasonZero, traceEvNone, 1)
+
+ mp = acquirem()
+ delete(notes, n)
+ releasem(mp)
+ }
+ return true
+}
+
+// checkTimeouts resumes goroutines that are waiting on a note which has reached its deadline.
+func checkTimeouts() {
+ now := nanotime()
+ for n, nt := range notesWithTimeout {
+ if n.key == note_cleared && now > nt.deadline {
+ n.key = note_timeout
+ goready(nt.gp, 1)
}
}
}
+
+var waitingForCallback *g
+
+// sleepUntilCallback puts the current goroutine to sleep until a callback is triggered.
+// It is currently only used by the callback routine of the syscall/js package.
+//go:linkname sleepUntilCallback syscall/js.sleepUntilCallback
+func sleepUntilCallback() {
+ waitingForCallback = getg()
+ gopark(nil, nil, waitReasonZero, traceEvNone, 1)
+ waitingForCallback = nil
+}
+
+// pauseSchedulerUntilCallback gets called from the scheduler and pauses the execution
+// of Go's WebAssembly code until a callback is triggered. Then it checks for note timeouts
+// and resumes goroutines that are waiting for a callback.
+func pauseSchedulerUntilCallback() bool {
+ if waitingForCallback == nil && len(notesWithTimeout) == 0 {
+ return false
+ }
+
+ pause()
+ checkTimeouts()
+ if waitingForCallback != nil {
+ goready(waitingForCallback, 1)
+ }
+ return true
+}
+
+// pause pauses the execution of Go's WebAssembly code until a callback is triggered.
+func pause()
+
+// scheduleCallback tells the WebAssembly environment to trigger a callback after ms milliseconds.
+// It returns a timer id that can be used with clearScheduledCallback.
+func scheduleCallback(ms int64) int32
+
+// clearScheduledCallback clears a callback scheduled by scheduleCallback.
+func clearScheduledCallback(id int32)
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index 4cb0e84db3..6e01d70f75 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -282,3 +282,9 @@ func notetsleepg(n *note, ns int64) bool {
exitsyscall()
return ok
}
+
+func pauseSchedulerUntilCallback() bool {
+ return false
+}
+
+func checkTimeouts() {}
diff --git a/src/runtime/map.go b/src/runtime/map.go
index cc1358a977..0e00f12974 100644
--- a/src/runtime/map.go
+++ b/src/runtime/map.go
@@ -707,14 +707,13 @@ search:
} else if t.key.kind&kindNoPointers == 0 {
memclrHasPointers(k, t.key.size)
}
- // Only clear value if there are pointers in it.
- if t.indirectvalue || t.elem.kind&kindNoPointers == 0 {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
- if t.indirectvalue {
- *(*unsafe.Pointer)(v) = nil
- } else {
- memclrHasPointers(v, t.elem.size)
- }
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*uintptr(t.keysize)+i*uintptr(t.valuesize))
+ if t.indirectvalue {
+ *(*unsafe.Pointer)(v) = nil
+ } else if t.elem.kind&kindNoPointers == 0 {
+ memclrHasPointers(v, t.elem.size)
+ } else {
+ memclrNoHeapPointers(v, t.elem.size)
}
b.tophash[i] = empty
h.count--
diff --git a/src/runtime/map_fast32.go b/src/runtime/map_fast32.go
index 296569772b..bf0b23604b 100644
--- a/src/runtime/map_fast32.go
+++ b/src/runtime/map_fast32.go
@@ -293,10 +293,11 @@ search:
if t.key.kind&kindNoPointers == 0 {
memclrHasPointers(k, t.key.size)
}
- // Only clear value if there are pointers in it.
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
if t.elem.kind&kindNoPointers == 0 {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*4+i*uintptr(t.valuesize))
memclrHasPointers(v, t.elem.size)
+ } else {
+ memclrNoHeapPointers(v, t.elem.size)
}
b.tophash[i] = empty
h.count--
diff --git a/src/runtime/map_fast64.go b/src/runtime/map_fast64.go
index aa3eff8ac8..4bde9e2be0 100644
--- a/src/runtime/map_fast64.go
+++ b/src/runtime/map_fast64.go
@@ -293,10 +293,11 @@ search:
if t.key.kind&kindNoPointers == 0 {
memclrHasPointers(k, t.key.size)
}
- // Only clear value if there are pointers in it.
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
if t.elem.kind&kindNoPointers == 0 {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*8+i*uintptr(t.valuesize))
memclrHasPointers(v, t.elem.size)
+ } else {
+ memclrNoHeapPointers(v, t.elem.size)
}
b.tophash[i] = empty
h.count--
diff --git a/src/runtime/map_faststr.go b/src/runtime/map_faststr.go
index fa21dcae7e..415bbff143 100644
--- a/src/runtime/map_faststr.go
+++ b/src/runtime/map_faststr.go
@@ -314,10 +314,11 @@ search:
}
// Clear key's pointer.
k.str = nil
- // Only clear value if there are pointers in it.
+ v := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
if t.elem.kind&kindNoPointers == 0 {
- v := add(unsafe.Pointer(b), dataOffset+bucketCnt*2*sys.PtrSize+i*uintptr(t.valuesize))
memclrHasPointers(v, t.elem.size)
+ } else {
+ memclrNoHeapPointers(v, t.elem.size)
}
b.tophash[i] = empty
h.count--
diff --git a/src/runtime/map_test.go b/src/runtime/map_test.go
index 0f20c84e77..4713ce25ec 100644
--- a/src/runtime/map_test.go
+++ b/src/runtime/map_test.go
@@ -435,11 +435,11 @@ func TestEmptyKeyAndValue(t *testing.T) {
// ("quick keys") as well as long keys.
func TestSingleBucketMapStringKeys_DupLen(t *testing.T) {
testMapLookups(t, map[string]string{
- "x": "x1val",
- "xx": "x2val",
- "foo": "fooval",
- "bar": "barval", // same key length as "foo"
- "xxxx": "x4val",
+ "x": "x1val",
+ "xx": "x2val",
+ "foo": "fooval",
+ "bar": "barval", // same key length as "foo"
+ "xxxx": "x4val",
strings.Repeat("x", 128): "longval1",
strings.Repeat("y", 128): "longval2",
})
@@ -1045,3 +1045,89 @@ func TestDeferDeleteSlow(t *testing.T) {
t.Errorf("want 0 elements, got %d", len(m))
}
}
+
+// TestIncrementAfterDeleteValueInt and other test Issue 25936.
+// Value types int, int32, int64 are affected. Value type string
+// works as expected.
+func TestIncrementAfterDeleteValueInt(t *testing.T) {
+ const key1 = 12
+ const key2 = 13
+
+ m := make(map[int]int)
+ m[key1] = 99
+ delete(m, key1)
+ m[key2]++
+ if n2 := m[key2]; n2 != 1 {
+ t.Errorf("incremented 0 to %d", n2)
+ }
+}
+
+func TestIncrementAfterDeleteValueInt32(t *testing.T) {
+ const key1 = 12
+ const key2 = 13
+
+ m := make(map[int]int32)
+ m[key1] = 99
+ delete(m, key1)
+ m[key2]++
+ if n2 := m[key2]; n2 != 1 {
+ t.Errorf("incremented 0 to %d", n2)
+ }
+}
+
+func TestIncrementAfterDeleteValueInt64(t *testing.T) {
+ const key1 = 12
+ const key2 = 13
+
+ m := make(map[int]int64)
+ m[key1] = 99
+ delete(m, key1)
+ m[key2]++
+ if n2 := m[key2]; n2 != 1 {
+ t.Errorf("incremented 0 to %d", n2)
+ }
+}
+
+func TestIncrementAfterDeleteKeyStringValueInt(t *testing.T) {
+ const key1 = ""
+ const key2 = "x"
+
+ m := make(map[string]int)
+ m[key1] = 99
+ delete(m, key1)
+ m[key2] += 1
+ if n2 := m[key2]; n2 != 1 {
+ t.Errorf("incremented 0 to %d", n2)
+ }
+}
+
+func TestIncrementAfterDeleteKeyValueString(t *testing.T) {
+ const key1 = ""
+ const key2 = "x"
+
+ m := make(map[string]string)
+ m[key1] = "99"
+ delete(m, key1)
+ m[key2] += "1"
+ if n2 := m[key2]; n2 != "1" {
+ t.Errorf("appended '1' to empty (nil) string, got %s", n2)
+ }
+}
+
+// TestIncrementAfterBulkClearKeyStringValueInt tests that map bulk
+// deletion (mapclear) still works as expected. Note that it was not
+// affected by Issue 25936.
+func TestIncrementAfterBulkClearKeyStringValueInt(t *testing.T) {
+ const key1 = ""
+ const key2 = "x"
+
+ m := make(map[string]int)
+ m[key1] = 99
+ for k := range m {
+ delete(m, k)
+ }
+ m[key2]++
+ if n2 := m[key2]; n2 != 1 {
+ t.Errorf("incremented 0 to %d", n2)
+ }
+}
diff --git a/src/runtime/memclr_386.s b/src/runtime/memclr_386.s
index 7d5dd38c0a..a6703b3641 100644
--- a/src/runtime/memclr_386.s
+++ b/src/runtime/memclr_386.s
@@ -16,6 +16,7 @@ TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-8
// MOVOU seems always faster than REP STOSL.
tail:
+ // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing.
TESTL BX, BX
JEQ _0
CMPL BX, $2
@@ -38,7 +39,6 @@ tail:
JBE _65through128
CMPL BX, $256
JBE _129through256
- // TODO: use branch table and BSR to make this just a single dispatch
loop:
MOVOU X0, 0(DI)
diff --git a/src/runtime/memclr_amd64.s b/src/runtime/memclr_amd64.s
index 63730eebfb..d79078fd00 100644
--- a/src/runtime/memclr_amd64.s
+++ b/src/runtime/memclr_amd64.s
@@ -17,6 +17,7 @@ TEXT runtime·memclrNoHeapPointers(SB), NOSPLIT, $0-16
// MOVOU seems always faster than REP STOSQ.
tail:
+ // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing.
TESTQ BX, BX
JEQ _0
CMPQ BX, $2
@@ -39,7 +40,6 @@ tail:
JBE _129through256
CMPB internal∕cpu·X86+const_offsetX86HasAVX2(SB), $1
JE loop_preheader_avx2
- // TODO: use branch table and BSR to make this just a single dispatch
// TODO: for really big clears, use MOVNTDQ, even without AVX2.
loop:
diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s
index 1bf86a5453..172ea40820 100644
--- a/src/runtime/memmove_386.s
+++ b/src/runtime/memmove_386.s
@@ -39,6 +39,7 @@ TEXT runtime·memmove(SB), NOSPLIT, $0-12
// 128 because that is the maximum SSE register load (loading all data
// into registers lets us ignore copy direction).
tail:
+ // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing.
TESTL BX, BX
JEQ move_0
CMPL BX, $2
@@ -58,7 +59,6 @@ tail:
JBE move_33through64
CMPL BX, $128
JBE move_65through128
- // TODO: use branch table and BSR to make this just a single dispatch
nosse2:
/*
diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s
index a671baf383..cb5cd02e45 100644
--- a/src/runtime/memmove_amd64.s
+++ b/src/runtime/memmove_amd64.s
@@ -43,6 +43,8 @@ tail:
// registers before writing it back. move_256through2048 on the other
// hand can be used only when the memory regions don't overlap or the copy
// direction is forward.
+ //
+ // BSR+branch table make almost all memmove/memclr benchmarks worse. Not worth doing.
TESTQ BX, BX
JEQ move_0
CMPQ BX, $2
@@ -63,7 +65,6 @@ tail:
JBE move_65through128
CMPQ BX, $256
JBE move_129through256
- // TODO: use branch table and BSR to make this just a single dispatch
TESTB $1, runtime·useAVXmemmove(SB)
JNZ avxUnaligned
diff --git a/src/runtime/netpoll_kqueue.go b/src/runtime/netpoll_kqueue.go
index 4d5d1a4ea8..0f73bf385e 100644
--- a/src/runtime/netpoll_kqueue.go
+++ b/src/runtime/netpoll_kqueue.go
@@ -10,12 +10,6 @@ package runtime
import "unsafe"
-func kqueue() int32
-
-//go:noescape
-func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
-func closeonexec(fd int32)
-
var (
kq int32 = -1
)
diff --git a/src/runtime/os_darwin.go b/src/runtime/os_darwin.go
index 55f938cd80..ff375004a3 100644
--- a/src/runtime/os_darwin.go
+++ b/src/runtime/os_darwin.go
@@ -7,38 +7,63 @@ package runtime
import "unsafe"
type mOS struct {
- machport uint32 // return address for mach ipc
- waitsema uint32 // semaphore for parking on locks
+ initialized bool
+ mutex pthreadmutex
+ cond pthreadcond
+ count int
}
-//go:noescape
-func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
-
-func mach_reply_port() uint32
-func mach_task_self() uint32
-func mach_thread_self() uint32
-
-//go:noescape
-func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32
-
func unimplemented(name string) {
println(name, "not implemented")
*(*int)(unsafe.Pointer(uintptr(1231))) = 1231
}
//go:nosplit
-func semawakeup(mp *m) {
- mach_semrelease(mp.waitsema)
+func semacreate(mp *m) {
+ if mp.initialized {
+ return
+ }
+ mp.initialized = true
+ if err := pthread_mutex_init(&mp.mutex, nil); err != 0 {
+ throw("pthread_mutex_init")
+ }
+ if err := pthread_cond_init(&mp.cond, nil); err != 0 {
+ throw("pthread_cond_init")
+ }
}
//go:nosplit
-func semacreate(mp *m) {
- if mp.waitsema != 0 {
- return
+func semasleep(ns int64) int32 {
+ mp := getg().m
+ pthread_mutex_lock(&mp.mutex)
+ for {
+ if mp.count > 0 {
+ mp.count--
+ pthread_mutex_unlock(&mp.mutex)
+ return 0
+ }
+ if ns >= 0 {
+ var t timespec
+ t.set_nsec(ns)
+ err := pthread_cond_timedwait_relative_np(&mp.cond, &mp.mutex, &t)
+ if err == _ETIMEDOUT {
+ pthread_mutex_unlock(&mp.mutex)
+ return -1
+ }
+ } else {
+ pthread_cond_wait(&mp.cond, &mp.mutex)
+ }
}
- systemstack(func() {
- mp.waitsema = mach_semcreate()
- })
+}
+
+//go:nosplit
+func semawakeup(mp *m) {
+ pthread_mutex_lock(&mp.mutex)
+ mp.count++
+ if mp.count > 0 {
+ pthread_cond_signal(&mp.cond)
+ }
+ pthread_mutex_unlock(&mp.mutex)
}
// BSD interface for threading.
@@ -206,7 +231,6 @@ func mpreinit(mp *m) {
func minit() {
// The alternate signal stack is buggy on arm and arm64.
// The signal handler handles it directly.
- // The sigaltstack assembly function does nothing.
if GOARCH != "arm" && GOARCH != "arm64" {
minitSignalStack()
}
@@ -223,268 +247,6 @@ func unminit() {
}
}
-// Mach IPC, to get at semaphores
-// Definitions are in /usr/include/mach on a Mac.
-
-func macherror(r int32, fn string) {
- print("mach error ", fn, ": ", r, "\n")
- throw("mach error")
-}
-
-const _DebugMach = false
-
-var zerondr machndr
-
-func mach_msgh_bits(a, b uint32) uint32 {
- return a | b<<8
-}
-
-func mach_msg(h *machheader, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32 {
- // TODO: Loop on interrupt.
- return mach_msg_trap(unsafe.Pointer(h), op, send_size, rcv_size, rcv_name, timeout, notify)
-}
-
-// Mach RPC (MIG)
-const (
- _MinMachMsg = 48
- _MachReply = 100
-)
-
-type codemsg struct {
- h machheader
- ndr machndr
- code int32
-}
-
-func machcall(h *machheader, maxsize int32, rxsize int32) int32 {
- _g_ := getg()
- port := _g_.m.machport
- if port == 0 {
- port = mach_reply_port()
- _g_.m.machport = port
- }
-
- h.msgh_bits |= mach_msgh_bits(_MACH_MSG_TYPE_COPY_SEND, _MACH_MSG_TYPE_MAKE_SEND_ONCE)
- h.msgh_local_port = port
- h.msgh_reserved = 0
- id := h.msgh_id
-
- if _DebugMach {
- p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
- print("send:\t")
- var i uint32
- for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
- print(" ", p[i])
- if i%8 == 7 {
- print("\n\t")
- }
- }
- if i%8 != 0 {
- print("\n")
- }
- }
- ret := mach_msg(h, _MACH_SEND_MSG|_MACH_RCV_MSG, h.msgh_size, uint32(maxsize), port, 0, 0)
- if ret != 0 {
- if _DebugMach {
- print("mach_msg error ", ret, "\n")
- }
- return ret
- }
- if _DebugMach {
- p := (*[10000]unsafe.Pointer)(unsafe.Pointer(h))
- var i uint32
- for i = 0; i < h.msgh_size/uint32(unsafe.Sizeof(p[0])); i++ {
- print(" ", p[i])
- if i%8 == 7 {
- print("\n\t")
- }
- }
- if i%8 != 0 {
- print("\n")
- }
- }
- if h.msgh_id != id+_MachReply {
- if _DebugMach {
- print("mach_msg _MachReply id mismatch ", h.msgh_id, " != ", id+_MachReply, "\n")
- }
- return -303 // MIG_REPLY_MISMATCH
- }
- // Look for a response giving the return value.
- // Any call can send this back with an error,
- // and some calls only have return values so they
- // send it back on success too. I don't quite see how
- // you know it's one of these and not the full response
- // format, so just look if the message is right.
- c := (*codemsg)(unsafe.Pointer(h))
- if uintptr(h.msgh_size) == unsafe.Sizeof(*c) && h.msgh_bits&_MACH_MSGH_BITS_COMPLEX == 0 {
- if _DebugMach {
- print("mig result ", c.code, "\n")
- }
- return c.code
- }
- if h.msgh_size != uint32(rxsize) {
- if _DebugMach {
- print("mach_msg _MachReply size mismatch ", h.msgh_size, " != ", rxsize, "\n")
- }
- return -307 // MIG_ARRAY_TOO_LARGE
- }
- return 0
-}
-
-// Semaphores!
-
-const (
- tmach_semcreate = 3418
- rmach_semcreate = tmach_semcreate + _MachReply
-
- tmach_semdestroy = 3419
- rmach_semdestroy = tmach_semdestroy + _MachReply
-
- _KERN_ABORTED = 14
- _KERN_OPERATION_TIMED_OUT = 49
-)
-
-type tmach_semcreatemsg struct {
- h machheader
- ndr machndr
- policy int32
- value int32
-}
-
-type rmach_semcreatemsg struct {
- h machheader
- body machbody
- semaphore machport
-}
-
-type tmach_semdestroymsg struct {
- h machheader
- body machbody
- semaphore machport
-}
-
-func mach_semcreate() uint32 {
- var m [256]uint8
- tx := (*tmach_semcreatemsg)(unsafe.Pointer(&m))
- rx := (*rmach_semcreatemsg)(unsafe.Pointer(&m))
-
- tx.h.msgh_bits = 0
- tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
- tx.h.msgh_remote_port = mach_task_self()
- tx.h.msgh_id = tmach_semcreate
- tx.ndr = zerondr
-
- tx.policy = 0 // 0 = SYNC_POLICY_FIFO
- tx.value = 0
-
- for {
- r := machcall(&tx.h, int32(unsafe.Sizeof(m)), int32(unsafe.Sizeof(*rx)))
- if r == 0 {
- break
- }
- if r == _KERN_ABORTED { // interrupted
- continue
- }
- macherror(r, "semaphore_create")
- }
- if rx.body.msgh_descriptor_count != 1 {
- unimplemented("mach_semcreate desc count")
- }
- return rx.semaphore.name
-}
-
-func mach_semdestroy(sem uint32) {
- var m [256]uint8
- tx := (*tmach_semdestroymsg)(unsafe.Pointer(&m))
-
- tx.h.msgh_bits = _MACH_MSGH_BITS_COMPLEX
- tx.h.msgh_size = uint32(unsafe.Sizeof(*tx))
- tx.h.msgh_remote_port = mach_task_self()
- tx.h.msgh_id = tmach_semdestroy
- tx.body.msgh_descriptor_count = 1
- tx.semaphore.name = sem
- tx.semaphore.disposition = _MACH_MSG_TYPE_MOVE_SEND
- tx.semaphore._type = 0
-
- for {
- r := machcall(&tx.h, int32(unsafe.Sizeof(m)), 0)
- if r == 0 {
- break
- }
- if r == _KERN_ABORTED { // interrupted
- continue
- }
- macherror(r, "semaphore_destroy")
- }
-}
-
-// The other calls have simple system call traps in sys_darwin_{amd64,386}.s
-
-func mach_semaphore_wait(sema uint32) int32
-func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
-func mach_semaphore_signal(sema uint32) int32
-func mach_semaphore_signal_all(sema uint32) int32
-
-func semasleep1(ns int64) int32 {
- _g_ := getg()
-
- if ns >= 0 {
- var nsecs int32
- secs := timediv(ns, 1000000000, &nsecs)
- r := mach_semaphore_timedwait(_g_.m.waitsema, uint32(secs), uint32(nsecs))
- if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT {
- return -1
- }
- if r != 0 {
- macherror(r, "semaphore_wait")
- }
- return 0
- }
-
- for {
- r := mach_semaphore_wait(_g_.m.waitsema)
- if r == 0 {
- break
- }
- // Note: We don't know how this call (with no timeout) can get _KERN_OPERATION_TIMED_OUT,
- // but it does reliably, though at a very low rate, on OS X 10.8, 10.9, 10.10, and 10.11.
- // See golang.org/issue/17161.
- if r == _KERN_ABORTED || r == _KERN_OPERATION_TIMED_OUT { // interrupted
- continue
- }
- macherror(r, "semaphore_wait")
- }
- return 0
-}
-
-//go:nosplit
-func semasleep(ns int64) int32 {
- var r int32
- systemstack(func() {
- r = semasleep1(ns)
- })
- return r
-}
-
-//go:nosplit
-func mach_semrelease(sem uint32) {
- for {
- r := mach_semaphore_signal(sem)
- if r == 0 {
- break
- }
- if r == _KERN_ABORTED { // interrupted
- continue
- }
-
- // mach_semrelease must be completely nosplit,
- // because it is called from Go code.
- // If we're going to die, start that process on the system stack
- // to avoid a Go stack split.
- systemstack(func() { macherror(r, "semaphore_signal") })
- }
-}
-
//go:nosplit
func osyield() {
usleep(1)
@@ -499,24 +261,6 @@ const (
_SS_DISABLE = 4
)
-//go:noescape
-func sigprocmask(how int32, new, old *sigset)
-
-//go:noescape
-func sigaction(mode uint32, new *sigactiont, old *usigactiont)
-
-//go:noescape
-func sigaltstack(new, old *stackt)
-
-// darwin/arm64 uses registers instead of stack-based arguments.
-// TODO: does this matter?
-func sigtramp(fn uintptr, infostyle, sig uint32, info *siginfo, ctx unsafe.Pointer)
-
-//go:noescape
-func setitimer(mode int32, new, old *itimerval)
-
-func raiseproc(sig uint32)
-
//extern SigTabTT runtime·sigtab[];
type sigset uint32
@@ -526,14 +270,20 @@ var sigset_all = ^sigset(0)
//go:nosplit
//go:nowritebarrierrec
func setsig(i uint32, fn uintptr) {
- var sa sigactiont
+ var sa usigactiont
sa.sa_flags = _SA_SIGINFO | _SA_ONSTACK | _SA_RESTART
sa.sa_mask = ^uint32(0)
- sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp)) // runtime·sigtramp's job is to call into real handler
+ if fn == funcPC(sighandler) {
+ fn = funcPC(sigtramp)
+ }
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = fn
sigaction(i, &sa, nil)
}
+// sigtramp is the callback from libc when a signal is received.
+// It is called with the C calling convention.
+func sigtramp()
+
//go:nosplit
//go:nowritebarrierrec
func setsigstack(i uint32) {
@@ -543,9 +293,8 @@ func setsigstack(i uint32) {
if osa.sa_flags&_SA_ONSTACK != 0 {
return
}
- var sa sigactiont
+ var sa usigactiont
*(*uintptr)(unsafe.Pointer(&sa.__sigaction_u)) = handler
- sa.sa_tramp = unsafe.Pointer(funcPC(sigtramp))
sa.sa_mask = osa.sa_mask
sa.sa_flags = osa.sa_flags | _SA_ONSTACK
sigaction(i, &sa, nil)
diff --git a/src/runtime/os_dragonfly.go b/src/runtime/os_dragonfly.go
index 2c9a78ca7b..eb7e159d35 100644
--- a/src/runtime/os_dragonfly.go
+++ b/src/runtime/os_dragonfly.go
@@ -49,6 +49,12 @@ func sys_umtx_wakeup(addr *uint32, val int32) int32
func osyield()
+func kqueue() int32
+
+//go:noescape
+func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+func closeonexec(fd int32)
+
const stackSystem = 0
// From DragonFly's <sys/sysctl.h>
diff --git a/src/runtime/os_freebsd.go b/src/runtime/os_freebsd.go
index b3fc6a34ac..631dc20ab4 100644
--- a/src/runtime/os_freebsd.go
+++ b/src/runtime/os_freebsd.go
@@ -34,6 +34,12 @@ func sys_umtx_op(addr *uint32, mode int32, val uint32, uaddr1 uintptr, ut *umtx_
func osyield()
+func kqueue() int32
+
+//go:noescape
+func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+func closeonexec(fd int32)
+
// From FreeBSD's <sys/sysctl.h>
const (
_CTL_HW = 6
diff --git a/src/runtime/os_netbsd.go b/src/runtime/os_netbsd.go
index 1a92619354..a9bf407a36 100644
--- a/src/runtime/os_netbsd.go
+++ b/src/runtime/os_netbsd.go
@@ -68,6 +68,12 @@ func lwp_self() int32
func osyield()
+func kqueue() int32
+
+//go:noescape
+func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+func closeonexec(fd int32)
+
const (
_ESRCH = 3
_ETIMEDOUT = 60
diff --git a/src/runtime/os_openbsd.go b/src/runtime/os_openbsd.go
index 432c468a8b..c359ceb280 100644
--- a/src/runtime/os_openbsd.go
+++ b/src/runtime/os_openbsd.go
@@ -55,6 +55,12 @@ func thrwakeup(ident uintptr, n int32) int32
func osyield()
+func kqueue() int32
+
+//go:noescape
+func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
+func closeonexec(fd int32)
+
const (
_ESRCH = 3
_EAGAIN = 35
diff --git a/src/runtime/panic.go b/src/runtime/panic.go
index 9ba7e1063f..ce367cfa70 100644
--- a/src/runtime/panic.go
+++ b/src/runtime/panic.go
@@ -716,6 +716,12 @@ func startpanic_m() bool {
// happen (even if we're not in one of these situations).
_g_.m.mallocing++
+ // If we're dying because of a bad lock count, set it to a
+ // good lock count so we don't recursively panic below.
+ if _g_.m.locks < 0 {
+ _g_.m.locks = 1
+ }
+
switch _g_.m.dying {
case 0:
_g_.m.dying = 1
diff --git a/src/runtime/pprof/proto.go b/src/runtime/pprof/proto.go
index d67c3a2865..1cf3a5154f 100644
--- a/src/runtime/pprof/proto.go
+++ b/src/runtime/pprof/proto.go
@@ -11,7 +11,6 @@ import (
"io"
"io/ioutil"
"runtime"
- "sort"
"strconv"
"time"
"unsafe"
@@ -48,10 +47,26 @@ type profileBuilder struct {
}
type memMap struct {
- start uintptr
- end uintptr
+ // initialized as reading mapping
+ start uintptr
+ end uintptr
+ offset uint64
+ file, buildID string
+
+ funcs symbolizeFlag
}
+// symbolizeFlag keeps track of symbolization result.
+// 0 : no symbol lookup was performed
+// 1<<0 (lookupTried) : symbol lookup was performed
+// 1<<1 (lookupFailed): symbol lookup was performed but failed
+type symbolizeFlag uint8
+
+const (
+ lookupTried symbolizeFlag = 1 << iota
+ lookupFailed symbolizeFlag = 1 << iota
+)
+
const (
// message Profile
tagProfile_SampleType = 1 // repeated ValueType
@@ -171,7 +186,7 @@ func (b *profileBuilder) pbLine(tag int, funcID uint64, line int64) {
}
// pbMapping encodes a Mapping message to b.pb.
-func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file, buildID string) {
+func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file, buildID string, hasFuncs bool) {
start := b.pb.startMessage()
b.pb.uint64Opt(tagMapping_ID, id)
b.pb.uint64Opt(tagMapping_Start, base)
@@ -179,8 +194,15 @@ func (b *profileBuilder) pbMapping(tag int, id, base, limit, offset uint64, file
b.pb.uint64Opt(tagMapping_Offset, offset)
b.pb.int64Opt(tagMapping_Filename, b.stringIndex(file))
b.pb.int64Opt(tagMapping_BuildID, b.stringIndex(buildID))
- // TODO: Set any of HasInlineFrames, HasFunctions, HasFilenames, HasLineNumbers?
- // It seems like they should all be true, but they've never been set.
+ // TODO: we set HasFunctions if all symbols from samples were symbolized (hasFuncs).
+ // Decide what to do about HasInlineFrames and HasLineNumbers.
+ // Also, another approach to handle the mapping entry with
+ // incomplete symbolization results is to dupliace the mapping
+ // entry (but with different Has* fields values) and use
+ // different entries for symbolized locations and unsymbolized locations.
+ if hasFuncs {
+ b.pb.bool(tagMapping_HasFunctions, true)
+ }
b.pb.endMessage(tag, start)
}
@@ -205,6 +227,11 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 {
return 0
}
+ symbolizeResult := lookupTried
+ if frame.PC == 0 || frame.Function == "" || frame.File == "" || frame.Line == 0 {
+ symbolizeResult |= lookupFailed
+ }
+
if frame.PC == 0 {
// If we failed to resolve the frame, at least make up
// a reasonable call PC. This mostly happens in tests.
@@ -239,12 +266,14 @@ func (b *profileBuilder) locForPC(addr uintptr) uint64 {
}
frame, more = frames.Next()
}
- if len(b.mem) > 0 {
- i := sort.Search(len(b.mem), func(i int) bool {
- return b.mem[i].end > addr
- })
- if i < len(b.mem) && b.mem[i].start <= addr && addr < b.mem[i].end {
+ for i := range b.mem {
+ if b.mem[i].start <= addr && addr < b.mem[i].end {
b.pb.uint64Opt(tagLocation_MappingID, uint64(i+1))
+
+ m := b.mem[i]
+ m.funcs |= symbolizeResult
+ b.mem[i] = m
+ break
}
}
b.pb.endMessage(tagProfile_Location, start)
@@ -392,6 +421,11 @@ func (b *profileBuilder) build() {
b.pbSample(values, locs, labels)
}
+ for i, m := range b.mem {
+ hasFunctions := m.funcs == lookupTried // lookupTried but not lookupFailed
+ b.pbMapping(tagProfile_Mapping, uint64(i+1), uint64(m.start), uint64(m.end), m.offset, m.file, m.buildID, hasFunctions)
+ }
+
// TODO: Anything for tagProfile_DropFrames?
// TODO: Anything for tagProfile_KeepFrames?
@@ -506,6 +540,11 @@ func parseProcSelfMaps(data []byte, addMapping func(lo, hi, offset uint64, file,
}
func (b *profileBuilder) addMapping(lo, hi, offset uint64, file, buildID string) {
- b.mem = append(b.mem, memMap{uintptr(lo), uintptr(hi)})
- b.pbMapping(tagProfile_Mapping, uint64(len(b.mem)), lo, hi, offset, file, buildID)
+ b.mem = append(b.mem, memMap{
+ start: uintptr(lo),
+ end: uintptr(hi),
+ offset: offset,
+ file: file,
+ buildID: buildID,
+ })
}
diff --git a/src/runtime/pprof/proto_test.go b/src/runtime/pprof/proto_test.go
index 78bb84412f..36c345b6d9 100644
--- a/src/runtime/pprof/proto_test.go
+++ b/src/runtime/pprof/proto_test.go
@@ -8,7 +8,10 @@ import (
"bytes"
"encoding/json"
"fmt"
+ "internal/testenv"
"io/ioutil"
+ "os"
+ "os/exec"
"reflect"
"runtime"
"runtime/pprof/internal/profile"
@@ -225,3 +228,76 @@ func TestProcSelfMaps(t *testing.T) {
}
}
}
+
+// TestMapping checkes the mapping section of CPU profiles
+// has the HasFunctions field set correctly. If all PCs included
+// in the samples are successfully symbolized, the corresponding
+// mapping entry (in this test case, only one entry) should have
+// its HasFunctions field set true.
+// The test generates a CPU profile that includes PCs from C side
+// that the runtime can't symbolize. See ./testdata/mappingtest.
+func TestMapping(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+ testenv.MustHaveCGO(t)
+
+ prog := "./testdata/mappingtest/main.go"
+
+ // GoOnly includes only Go symbols that runtime will symbolize.
+ // Go+C includes C symbols that runtime will not symbolize.
+ for _, traceback := range []string{"GoOnly", "Go+C"} {
+ t.Run("traceback"+traceback, func(t *testing.T) {
+ cmd := exec.Command(testenv.GoToolPath(t), "run", prog)
+ if traceback != "GoOnly" {
+ cmd.Env = append(os.Environ(), "SETCGOTRACEBACK=1")
+ }
+ cmd.Stderr = new(bytes.Buffer)
+
+ out, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("failed to run the test program %q: %v\n%v", prog, err, cmd.Stderr)
+ }
+
+ prof, err := profile.Parse(bytes.NewReader(out))
+ if err != nil {
+ t.Fatalf("failed to parse the generated profile data: %v", err)
+ }
+ t.Logf("Profile: %s", prof)
+
+ hit := make(map[*profile.Mapping]bool)
+ miss := make(map[*profile.Mapping]bool)
+ for _, loc := range prof.Location {
+ if symbolized(loc) {
+ hit[loc.Mapping] = true
+ } else {
+ miss[loc.Mapping] = true
+ }
+ }
+ if len(miss) == 0 {
+ t.Log("no location with missing symbol info was sampled")
+ }
+
+ for _, m := range prof.Mapping {
+ if miss[m] && m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=true, but contains locations with failed symbolization", m)
+ continue
+ }
+ if !miss[m] && hit[m] && !m.HasFunctions {
+ t.Errorf("mapping %+v has HasFunctions=false, but all referenced locations from this lapping were symbolized successfully", m)
+ continue
+ }
+ }
+ })
+ }
+}
+
+func symbolized(loc *profile.Location) bool {
+ if len(loc.Line) == 0 {
+ return false
+ }
+ l := loc.Line[0]
+ f := l.Function
+ if l.Line == 0 || f == nil || f.Name == "" || f.Filename == "" {
+ return false
+ }
+ return true
+}
diff --git a/src/runtime/pprof/testdata/mappingtest/main.go b/src/runtime/pprof/testdata/mappingtest/main.go
new file mode 100644
index 0000000000..7850faab0d
--- /dev/null
+++ b/src/runtime/pprof/testdata/mappingtest/main.go
@@ -0,0 +1,105 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program outputs a CPU profile that includes
+// both Go and Cgo stacks. This is used by the mapping info
+// tests in runtime/pprof.
+//
+// If SETCGOTRACEBACK=1 is set, the CPU profile will includes
+// PCs from C side but they will not be symbolized.
+package main
+
+/*
+#include <stdint.h>
+#include <stdlib.h>
+
+int cpuHogCSalt1 = 0;
+int cpuHogCSalt2 = 0;
+
+void CPUHogCFunction() {
+ int foo = cpuHogCSalt1;
+ int i;
+ for (i = 0; i < 100000; i++) {
+ if (foo > 0) {
+ foo *= foo;
+ } else {
+ foo *= foo + 1;
+ }
+ cpuHogCSalt2 = foo;
+ }
+}
+
+struct CgoTracebackArg {
+ uintptr_t context;
+ uintptr_t sigContext;
+ uintptr_t *buf;
+ uintptr_t max;
+};
+
+void CollectCgoTraceback(void* parg) {
+ struct CgoTracebackArg* arg = (struct CgoTracebackArg*)(parg);
+ arg->buf[0] = (uintptr_t)(CPUHogCFunction);
+ arg->buf[1] = 0;
+};
+*/
+import "C"
+
+import (
+ "log"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "time"
+ "unsafe"
+)
+
+func init() {
+ if v := os.Getenv("SETCGOTRACEBACK"); v == "1" {
+ // Collect some PCs from C-side, but don't symbolize.
+ runtime.SetCgoTraceback(0, unsafe.Pointer(C.CollectCgoTraceback), nil, nil)
+ }
+}
+
+func main() {
+ go cpuHogGoFunction()
+ go cpuHogCFunction()
+ runtime.Gosched()
+
+ if err := pprof.StartCPUProfile(os.Stdout); err != nil {
+ log.Fatal("can't start CPU profile: ", err)
+ }
+ time.Sleep(1 * time.Second)
+ pprof.StopCPUProfile()
+
+ if err := os.Stdout.Close(); err != nil {
+ log.Fatal("can't write CPU profile: ", err)
+ }
+}
+
+var salt1 int
+var salt2 int
+
+func cpuHogGoFunction() {
+ // Generates CPU profile samples including a Go call path.
+ for {
+ foo := salt1
+ for i := 0; i < 1e5; i++ {
+ if foo > 0 {
+ foo *= foo
+ } else {
+ foo *= foo + 1
+ }
+ salt2 = foo
+ }
+ runtime.Gosched()
+ }
+}
+
+func cpuHogCFunction() {
+ // Generates CPU profile samples including a Cgo call path.
+ for {
+ C.CPUHogCFunction()
+ runtime.Gosched()
+ }
+}
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index e3549d367a..b5486321ed 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -263,6 +263,7 @@ func forcegchelper() {
// Gosched yields the processor, allowing other goroutines to run. It does not
// suspend the current goroutine, so execution resumes automatically.
func Gosched() {
+ checkTimeouts()
mcall(gosched_m)
}
@@ -282,6 +283,9 @@ func goschedguarded() {
// Reasons should be unique and descriptive.
// Do not re-use reasons, add new ones.
func gopark(unlockf func(*g, unsafe.Pointer) bool, lock unsafe.Pointer, reason waitReason, traceEv byte, traceskip int) {
+ if reason != waitReasonSleep {
+ checkTimeouts() // timeouts may expire while two goroutines keep the scheduler busy
+ }
mp := acquirem()
gp := mp.curg
status := readgstatus(gp)
@@ -513,6 +517,8 @@ func cpuinit() {
support_popcnt = cpu.X86.HasPOPCNT
support_sse2 = cpu.X86.HasSSE2
support_sse41 = cpu.X86.HasSSE41
+
+ arm64_support_atomics = cpu.ARM64.HasATOMICS
}
// The bootstrap sequence is:
@@ -2361,6 +2367,14 @@ stop:
return gp, false
}
+ // wasm only:
+ // Check if a goroutine is waiting for a callback from the WebAssembly host.
+ // If yes, pause the execution until a callback was triggered.
+ if pauseSchedulerUntilCallback() {
+ // A callback was triggered and caused at least one goroutine to wake up.
+ goto top
+ }
+
// Before we drop our P, make a snapshot of the allp slice,
// which can change underfoot once we no longer block
// safe-points. We don't need to snapshot the contents because
diff --git a/src/runtime/race.go b/src/runtime/race.go
index 09a8356770..0124e231fa 100644
--- a/src/runtime/race.go
+++ b/src/runtime/race.go
@@ -292,6 +292,7 @@ var racearenastart uintptr
var racearenaend uintptr
func racefuncenter(uintptr)
+func racefuncenterfp()
func racefuncexit()
func racereadrangepc1(uintptr, uintptr, uintptr)
func racewriterangepc1(uintptr, uintptr, uintptr)
diff --git a/src/runtime/race/race.go b/src/runtime/race/race.go
index 15e20112a8..f702c7a5d4 100644
--- a/src/runtime/race/race.go
+++ b/src/runtime/race/race.go
@@ -2,7 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64
+// +build race,linux,amd64 race,freebsd,amd64 race,darwin,amd64 race,windows,amd64 race,linux,ppc64le
package race
diff --git a/src/runtime/race_ppc64le.s b/src/runtime/race_ppc64le.s
new file mode 100644
index 0000000000..5c723e0f51
--- /dev/null
+++ b/src/runtime/race_ppc64le.s
@@ -0,0 +1,568 @@
+// Copyright 2018 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 race
+
+#include "go_asm.h"
+#include "go_tls.h"
+#include "funcdata.h"
+#include "textflag.h"
+
+// The following functions allow calling the clang-compiled race runtime directly
+// from Go code without going all the way through cgo.
+// First, it's much faster (up to 50% speedup for real Go programs).
+// Second, it eliminates race-related special cases from cgocall and scheduler.
+// Third, in long-term it will allow to remove cyclic runtime/race dependency on cmd/go.
+
+// A brief recap of the ppc64le calling convention.
+// Arguments are passed in R3, R4, R5 ...
+// SP must be 16-byte aligned.
+
+// Note that for ppc64x, LLVM follows the standard ABI and
+// expects arguments in registers, so these functions move
+// the arguments from storage to the registers expected
+// by the ABI.
+
+// When calling from Go to Clang tsan code:
+// R3 is the 1st argument and is usually the ThreadState*
+// R4-? are the 2nd, 3rd, 4th, etc. arguments
+
+// When calling racecalladdr:
+// R8 is the call target address
+
+// The race ctx is passed in R3 and loaded in
+// racecalladdr.
+//
+// The sequence used to get the race ctx:
+// MOVD runtime·tls_g(SB), R10 // offset to TLS
+// MOVD 0(R13)(R10*1), g // R13=TLS for this thread, g = R30
+// MOVD g_racectx(g), R3 // racectx == ThreadState
+
+// func runtime·RaceRead(addr uintptr)
+// Called from instrumented Go code
+TEXT runtime·raceread(SB), NOSPLIT, $0-8
+ MOVD addr+0(FP), R4
+ MOVD LR, R5 // caller of this?
+ // void __tsan_read(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_read(SB), R8
+ BR racecalladdr<>(SB)
+
+TEXT runtime·RaceRead(SB), NOSPLIT, $0-8
+ BR runtime·raceread(SB)
+
+// void runtime·racereadpc(void *addr, void *callpc, void *pc)
+TEXT runtime·racereadpc(SB), NOSPLIT, $0-24
+ MOVD addr+0(FP), R4
+ MOVD callpc+8(FP), R5
+ MOVD pc+16(FP), R6
+ // void __tsan_read_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_read_pc(SB), R8
+ BR racecalladdr<>(SB)
+
+// func runtime·RaceWrite(addr uintptr)
+// Called from instrumented Go code
+TEXT runtime·racewrite(SB), NOSPLIT, $0-8
+ MOVD addr+0(FP), R4
+ MOVD LR, R5 // caller has set LR via BL inst
+ // void __tsan_write(ThreadState *thr, void *addr, void *pc);
+ MOVD $__tsan_write(SB), R8
+ BR racecalladdr<>(SB)
+
+TEXT runtime·RaceWrite(SB), NOSPLIT, $0-8
+ JMP runtime·racewrite(SB)
+
+// void runtime·racewritepc(void *addr, void *callpc, void *pc)
+TEXT runtime·racewritepc(SB), NOSPLIT, $0-24
+ MOVD addr+0(FP), R4
+ MOVD callpc+8(FP), R5
+ MOVD pc+16(FP), R6
+ // void __tsan_write_pc(ThreadState *thr, void *addr, void *callpc, void *pc);
+ MOVD $__tsan_write_pc(SB), R8
+ BR racecalladdr<>(SB)
+
+// func runtime·RaceReadRange(addr, size uintptr)
+// Called from instrumented Go code.
+TEXT runtime·racereadrange(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), R4
+ MOVD size+8(FP), R5
+ MOVD LR, R6
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R8
+ BR racecalladdr<>(SB)
+
+// void runtime·racereadrangepc1(void *addr, uintptr sz, void *pc)
+TEXT runtime·racereadrangepc1(SB), NOSPLIT, $0-24
+ MOVD addr+0(FP), R4
+ MOVD size+8(FP), R5
+ MOVD pc+16(FP), R6
+ ADD $4, R6 // tsan wants return addr
+ // void __tsan_read_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_read_range(SB), R8
+ BR racecalladdr<>(SB)
+
+TEXT runtime·RaceReadRange(SB), NOSPLIT, $0-24
+ BR runtime·racereadrange(SB)
+
+// func runtime·RaceWriteRange(addr, size uintptr)
+// Called from instrumented Go code.
+TEXT runtime·racewriterange(SB), NOSPLIT, $0-16
+ MOVD addr+0(FP), R4
+ MOVD size+8(FP), R5
+ MOVD LR, R6
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R8
+ BR racecalladdr<>(SB)
+
+TEXT runtime·RaceWriteRange(SB), NOSPLIT, $0-16
+ BR runtime·racewriterange(SB)
+
+// void runtime·racewriterangepc1(void *addr, uintptr sz, void *pc)
+// Called from instrumented Go code
+TEXT runtime·racewriterangepc1(SB), NOSPLIT, $0-24
+ MOVD addr+0(FP), R4
+ MOVD size+8(FP), R5
+ MOVD pc+16(FP), R6
+ ADD $4, R6 // add 4 to inst offset?
+ // void __tsan_write_range(ThreadState *thr, void *addr, uintptr size, void *pc);
+ MOVD $__tsan_write_range(SB), R8
+ BR racecalladdr<>(SB)
+
+// Call a __tsan function from Go code.
+// R8 = tsan function address
+// R3 = *ThreadState a.k.a. g_racectx from g
+// R4 = addr passed to __tsan function
+//
+// Otherwise, setup goroutine context and invoke racecall. Other arguments already set.
+TEXT racecalladdr<>(SB), NOSPLIT, $0-0
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_racectx(g), R3 // goroutine context
+ // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
+ MOVD runtime·racearenastart(SB), R9
+ CMP R4, R9
+ BLT data
+ MOVD runtime·racearenaend(SB), R9
+ CMP R4, R9
+ BLT call
+data:
+ MOVD runtime·racedatastart(SB), R9
+ CMP R4, R9
+ BLT ret
+ MOVD runtime·racedataend(SB), R9
+ CMP R4, R9
+ BGT ret
+call:
+ // Careful!! racecall will save LR on its
+ // stack, which is OK as long as racecalladdr
+ // doesn't change in a way that generates a stack.
+ // racecall should return to the caller of
+ // recalladdr.
+ BR racecall<>(SB)
+ret:
+ RET
+
+// func runtime·racefuncenterfp()
+// Called from instrumented Go code.
+// Like racefuncenter but doesn't pass an arg, uses the caller pc
+// from the first slot on the stack.
+TEXT runtime·racefuncenterfp(SB), NOSPLIT, $0-0
+ MOVD 0(R1), R8
+ BR racefuncenter<>(SB)
+
+// func runtime·racefuncenter(pc uintptr)
+// Called from instrumented Go code.
+// Not used now since gc/racewalk.go doesn't pass the
+// correct caller pc and racefuncenterfp can do it.
+TEXT runtime·racefuncenter(SB), NOSPLIT, $0-8
+ MOVD callpc+0(FP), R8
+ BR racefuncenter<>(SB)
+
+// Common code for racefuncenter/racefuncenterfp
+// R11 = caller's return address
+TEXT racefuncenter<>(SB), NOSPLIT, $0-0
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState
+ MOVD R8, R4 // caller pc set by caller in R8
+ // void __tsan_func_enter(ThreadState *thr, void *pc);
+ MOVD $__tsan_func_enter(SB), R8
+ BR racecall<>(SB)
+ RET
+
+// func runtime·racefuncexit()
+// Called from Go instrumented code.
+TEXT runtime·racefuncexit(SB), NOSPLIT, $0-0
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState
+ // void __tsan_func_exit(ThreadState *thr);
+ MOVD $__tsan_func_exit(SB), R8
+ BR racecall<>(SB)
+
+// Atomic operations for sync/atomic package.
+// Some use the __tsan versions instead
+// R6 = addr of arguments passed to this function
+// R3, R4, R5 set in racecallatomic
+
+// Load atomic in tsan
+TEXT sync∕atomic·LoadInt32(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic32_load(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadInt64(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic64_load(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic64_load(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+ RET
+
+TEXT sync∕atomic·LoadUint32(SB), NOSPLIT, $0-0
+ BR sync∕atomic·LoadInt32(SB)
+
+TEXT sync∕atomic·LoadUint64(SB), NOSPLIT, $0-0
+ BR sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadUintptr(SB), NOSPLIT, $0-0
+ BR sync∕atomic·LoadInt64(SB)
+
+TEXT sync∕atomic·LoadPointer(SB), NOSPLIT, $0-0
+ BR sync∕atomic·LoadInt64(SB)
+
+// Store atomic in tsan
+TEXT sync∕atomic·StoreInt32(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic32_store(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·StoreInt64(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic64_store(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic64_store(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·StoreUint32(SB), NOSPLIT, $0-0
+ BR sync∕atomic·StoreInt32(SB)
+
+TEXT sync∕atomic·StoreUint64(SB), NOSPLIT, $0-0
+ BR sync∕atomic·StoreInt64(SB)
+
+TEXT sync∕atomic·StoreUintptr(SB), NOSPLIT, $0-0
+ BR sync∕atomic·StoreInt64(SB)
+
+// Swap in tsan
+TEXT sync∕atomic·SwapInt32(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic32_exchange(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·SwapInt64(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic64_exchange(ThreadState *thr, uptr cpc, uptr pc, u8 *a)
+ MOVD $__tsan_go_atomic64_exchange(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·SwapUint32(SB), NOSPLIT, $0-0
+ BR sync∕atomic·SwapInt32(SB)
+
+TEXT sync∕atomic·SwapUint64(SB), NOSPLIT, $0-0
+ BR sync∕atomic·SwapInt64(SB)
+
+TEXT sync∕atomic·SwapUintptr(SB), NOSPLIT, $0-0
+ BR sync∕atomic·SwapInt64(SB)
+
+// Add atomic in tsan
+TEXT sync∕atomic·AddInt32(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic32_fetch_add(SB), R8
+ ADD $64, R1, R6 // addr of caller's 1st arg
+ BL racecallatomic<>(SB)
+ // The tsan fetch_add result is not as expected by Go,
+ // so the 'add' must be added to the result.
+ MOVW add+8(FP), R3 // The tsa fetch_add does not return the
+ MOVW ret+16(FP), R4 // result as expected by go, so fix it.
+ ADD R3, R4, R3
+ MOVW R3, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddInt64(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic64_fetch_add(ThreadState *thr, uptr cpc, uptr pc, u8 *a);
+ MOVD $__tsan_go_atomic64_fetch_add(SB), R8
+ ADD $64, R1, R6 // addr of caller's 1st arg
+ BL racecallatomic<>(SB)
+ // The tsan fetch_add result is not as expected by Go,
+ // so the 'add' must be added to the result.
+ MOVD add+8(FP), R3
+ MOVD ret+16(FP), R4
+ ADD R3, R4, R3
+ MOVD R3, ret+16(FP)
+ RET
+
+TEXT sync∕atomic·AddUint32(SB), NOSPLIT, $0-0
+ BR sync∕atomic·AddInt32(SB)
+
+TEXT sync∕atomic·AddUint64(SB), NOSPLIT, $0-0
+ BR sync∕atomic·AddInt64(SB)
+
+TEXT sync∕atomic·AddUintptr(SB), NOSPLIT, $0-0
+ BR sync∕atomic·AddInt64(SB)
+
+// CompareAndSwap in tsan
+TEXT sync∕atomic·CompareAndSwapInt32(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_compare_exchange(
+ // ThreadState *thr, uptr cpc, uptr pc, u8 *a)
+ MOVD $__tsan_go_atomic32_compare_exchange(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·CompareAndSwapInt64(SB), NOSPLIT, $0-0
+ // void __tsan_go_atomic32_compare_exchange(
+ // ThreadState *thr, uptr cpc, uptr pc, u8 *a)
+ MOVD $__tsan_go_atomic64_compare_exchange(SB), R8
+ ADD $32, R1, R6 // addr of caller's 1st arg
+ BR racecallatomic<>(SB)
+
+TEXT sync∕atomic·CompareAndSwapUint32(SB), NOSPLIT, $0-0
+ BR sync∕atomic·CompareAndSwapInt32(SB)
+
+TEXT sync∕atomic·CompareAndSwapUint64(SB), NOSPLIT, $0-0
+ BR sync∕atomic·CompareAndSwapInt64(SB)
+
+TEXT sync∕atomic·CompareAndSwapUintptr(SB), NOSPLIT, $0-0
+ BR sync∕atomic·CompareAndSwapInt64(SB)
+
+// Common function used to call tsan's atomic functions
+// R3 = *ThreadState
+// R4 = TODO: What's this supposed to be?
+// R5 = caller pc
+// R6 = addr of incoming arg list
+// R8 contains addr of target function.
+TEXT racecallatomic<>(SB), NOSPLIT, $0-0
+ // Trigger SIGSEGV early if address passed to atomic function is bad.
+ MOVD (R6), R7 // 1st arg is addr
+ MOVD (R7), R9 // segv here if addr is bad
+ // Check that addr is within [arenastart, arenaend) or within [racedatastart, racedataend).
+ MOVD runtime·racearenastart(SB), R9
+ CMP R7, R9
+ BLT racecallatomic_data
+ MOVD runtime·racearenaend(SB), R9
+ CMP R7, R9
+ BLT racecallatomic_ok
+racecallatomic_data:
+ MOVD runtime·racedatastart(SB), R9
+ CMP R7, R9
+ BLT racecallatomic_ignore
+ MOVD runtime·racedataend(SB), R9
+ CMP R7, R9
+ BGE racecallatomic_ignore
+racecallatomic_ok:
+ // Addr is within the good range, call the atomic function.
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_racectx(g), R3 // goroutine racectx aka *ThreadState
+ MOVD R8, R5 // pc is the function called
+ MOVD (R1), R4 // caller pc from stack
+ BL racecall<>(SB) // BL needed to maintain stack consistency
+ RET //
+racecallatomic_ignore:
+ // Addr is outside the good range.
+ // Call __tsan_go_ignore_sync_begin to ignore synchronization during the atomic op.
+ // An attempt to synchronize on the address would cause crash.
+ MOVD R8, R15 // save the original function
+ MOVD R6, R17 // save the original arg list addr
+ MOVD $__tsan_go_ignore_sync_begin(SB), R8 // func addr to call
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_racectx(g), R3 // goroutine context
+ BL racecall<>(SB)
+ MOVD R15, R8 // restore the original function
+ MOVD R17, R6 // restore arg list addr
+ // Call the atomic function.
+ // racecall will call LLVM race code which might clobber r30 (g)
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+
+ MOVD g_racectx(g), R3
+ MOVD R8, R4 // pc being called same TODO as above
+ MOVD (R1), R5 // caller pc from latest LR
+ BL racecall<>(SB)
+ // Call __tsan_go_ignore_sync_end.
+ MOVD $__tsan_go_ignore_sync_end(SB), R8
+ MOVD g_racectx(g), R3 // goroutine context g should sitll be good?
+ BL racecall<>(SB)
+ RET
+
+// void runtime·racecall(void(*f)(...), ...)
+// Calls C function f from race runtime and passes up to 4 arguments to it.
+// The arguments are never heap-object-preserving pointers, so we pretend there are no arguments.
+TEXT runtime·racecall(SB), NOSPLIT, $0-0
+ MOVD fn+0(FP), R8
+ MOVD arg0+8(FP), R3
+ MOVD arg1+16(FP), R4
+ MOVD arg2+24(FP), R5
+ MOVD arg3+32(FP), R6
+ JMP racecall<>(SB)
+
+// Finds g0 and sets its stack
+// Arguments were loaded for call from Go to C
+TEXT racecall<>(SB), NOSPLIT, $0-0
+ // Set the LR slot for the ppc64 ABI
+ MOVD LR, R10
+ MOVD R10, 0(R1) // Go expectation
+ MOVD R10, 16(R1) // C ABI
+ // Get info from the current goroutine
+ MOVD runtime·tls_g(SB), R10 // g offset in TLS
+ MOVD 0(R13)(R10*1), g // R13 = current TLS
+ MOVD g_m(g), R7 // m for g
+ MOVD R1, R16 // callee-saved, preserved across C call
+ MOVD m_g0(R7), R10 // g0 for m
+ CMP R10, g // same g0?
+ BEQ call // already on g0
+ MOVD (g_sched+gobuf_sp)(R10), R1 // switch R1
+call:
+ MOVD R8, CTR // R8 = caller addr
+ MOVD R8, R12 // expected by PPC64 ABI
+ BL (CTR)
+ XOR R0, R0 // clear R0 on return from Clang
+ MOVD R16, R1 // restore R1; R16 nonvol in Clang
+ MOVD runtime·tls_g(SB), R10 // find correct g
+ MOVD 0(R13)(R10*1), g
+ MOVD 16(R1), R10 // LR was saved away, restore for return
+ MOVD R10, LR
+ RET
+
+// C->Go callback thunk that allows to call runtime·racesymbolize from C code.
+// Direct Go->C race call has only switched SP, finish g->g0 switch by setting correct g.
+// The overall effect of Go->C->Go call chain is similar to that of mcall.
+// RARG0 contains command code. RARG1 contains command-specific context.
+// See racecallback for command codes.
+TEXT runtime·racecallbackthunk(SB), NOSPLIT, $-8
+ // Handle command raceGetProcCmd (0) here.
+ // First, code below assumes that we are on curg, while raceGetProcCmd
+ // can be executed on g0. Second, it is called frequently, so will
+ // benefit from this fast path.
+ XOR R0, R0 // clear R0 since we came from C code
+ CMP R3, $0
+ BNE rest
+ // g0 TODO: Don't modify g here since R30 is nonvolatile
+ MOVD g, R9
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+ MOVD g_m(g), R3
+ MOVD m_p(R3), R3
+ MOVD p_racectx(R3), R3
+ MOVD R3, (R4)
+ MOVD R9, g // restore R30 ??
+ RET
+
+ // This is all similar to what cgo does
+ // Save registers according to the ppc64 ABI
+rest:
+ MOVD LR, R10 // save link register
+ MOVD R10, 16(R1)
+ MOVW CR, R10
+ MOVW R10, 8(R1)
+ MOVDU R1, -336(R1) // Allocate frame needed for register save area
+
+ MOVD R14, 40(R1)
+ MOVD R15, 48(R1)
+ MOVD R16, 56(R1)
+ MOVD R17, 64(R1)
+ MOVD R18, 72(R1)
+ MOVD R19, 80(R1)
+ MOVD R20, 88(R1)
+ MOVD R21, 96(R1)
+ MOVD R22, 104(R1)
+ MOVD R23, 112(R1)
+ MOVD R24, 120(R1)
+ MOVD R25, 128(R1)
+ MOVD R26, 136(R1)
+ MOVD R27, 144(R1)
+ MOVD R28, 152(R1)
+ MOVD R29, 160(R1)
+ MOVD g, 168(R1) // R30
+ MOVD R31, 176(R1)
+ FMOVD F14, 184(R1)
+ FMOVD F15, 192(R1)
+ FMOVD F16, 200(R1)
+ FMOVD F17, 208(R1)
+ FMOVD F18, 216(R1)
+ FMOVD F19, 224(R1)
+ FMOVD F20, 232(R1)
+ FMOVD F21, 240(R1)
+ FMOVD F22, 248(R1)
+ FMOVD F23, 256(R1)
+ FMOVD F24, 264(R1)
+ FMOVD F25, 272(R1)
+ FMOVD F26, 280(R1)
+ FMOVD F27, 288(R1)
+ FMOVD F28, 296(R1)
+ FMOVD F29, 304(R1)
+ FMOVD F30, 312(R1)
+ FMOVD F31, 320(R1)
+
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+
+ MOVD g_m(g), R7
+ MOVD m_g0(R7), g // set g = m-> g0
+ MOVD R3, cmd+0(FP) // can't use R1 here ?? use input args and assumer caller expects those?
+ MOVD R4, ctx+8(FP) // can't use R1 here ??
+ BL runtime·racecallback(SB)
+ // All registers are clobbered after Go code, reload.
+ MOVD runtime·tls_g(SB), R10
+ MOVD 0(R13)(R10*1), g
+
+ MOVD g_m(g), R7
+ MOVD m_curg(R7), g // restore g = m->curg
+ MOVD 40(R1), R14
+ MOVD 48(R1), R15
+ MOVD 56(R1), R16
+ MOVD 64(R1), R17
+ MOVD 72(R1), R18
+ MOVD 80(R1), R19
+ MOVD 88(R1), R20
+ MOVD 96(R1), R21
+ MOVD 104(R1), R22
+ MOVD 112(R1), R23
+ MOVD 120(R1), R24
+ MOVD 128(R1), R25
+ MOVD 136(R1), R26
+ MOVD 144(R1), R27
+ MOVD 152(R1), R28
+ MOVD 160(R1), R29
+ MOVD 168(R1), g // R30
+ MOVD 176(R1), R31
+ FMOVD 184(R1), F14
+ FMOVD 192(R1), F15
+ FMOVD 200(R1), F16
+ FMOVD 208(R1), F17
+ FMOVD 216(R1), F18
+ FMOVD 224(R1), F19
+ FMOVD 232(R1), F20
+ FMOVD 240(R1), F21
+ FMOVD 248(R1), F22
+ FMOVD 256(R1), F23
+ FMOVD 264(R1), F24
+ FMOVD 272(R1), F25
+ FMOVD 280(R1), F26
+ FMOVD 288(R1), F27
+ FMOVD 296(R1), F28
+ FMOVD 304(R1), F29
+ FMOVD 312(R1), F30
+ FMOVD 320(R1), F31
+
+ ADD $336, R1
+ MOVD 8(R1), R10
+ MOVFL R10, $0xff // Restore of CR
+ MOVD 16(R1), R10 // needed?
+ MOVD R10, LR
+ RET
+
+// tls_g, g value for each thread in TLS
+GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8
diff --git a/src/runtime/rt0_darwin_arm64.s b/src/runtime/rt0_darwin_arm64.s
index 960de06044..d039a8e0ab 100644
--- a/src/runtime/rt0_darwin_arm64.s
+++ b/src/runtime/rt0_darwin_arm64.s
@@ -8,8 +8,7 @@
// supports external linking.
TEXT _rt0_arm64_darwin(SB),NOSPLIT|NOFRAME,$0
MOVD $42, R0
- MOVD $1, R16 // SYS_exit
- SVC $0x80
+ BL libc_exit(SB)
// When linking with -buildmode=c-archive or -buildmode=c-shared,
// this symbol is called from a global initialization function.
@@ -27,18 +26,21 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$168
MOVD R25, 72(RSP)
MOVD R26, 80(RSP)
MOVD R27, 88(RSP)
- FMOVD F8, 96(RSP)
- FMOVD F9, 104(RSP)
- FMOVD F10, 112(RSP)
- FMOVD F11, 120(RSP)
- FMOVD F12, 128(RSP)
- FMOVD F13, 136(RSP)
- FMOVD F14, 144(RSP)
- FMOVD F15, 152(RSP)
+ MOVD g, 96(RSP)
+ FMOVD F8, 104(RSP)
+ FMOVD F9, 112(RSP)
+ FMOVD F10, 120(RSP)
+ FMOVD F11, 128(RSP)
+ FMOVD F12, 136(RSP)
+ FMOVD F13, 144(RSP)
+ FMOVD F14, 152(RSP)
+ FMOVD F15, 160(RSP)
MOVD R0, _rt0_arm64_darwin_lib_argc<>(SB)
MOVD R1, _rt0_arm64_darwin_lib_argv<>(SB)
+ MOVD $0, g // initialize g to nil
+
// Synchronous initialization.
MOVD $runtime·libpreinit(SB), R4
BL (R4)
@@ -59,14 +61,16 @@ TEXT _rt0_arm64_darwin_lib(SB),NOSPLIT,$168
MOVD 72(RSP), R25
MOVD 80(RSP), R26
MOVD 88(RSP), R27
- FMOVD 96(RSP), F8
- FMOVD 104(RSP), F9
- FMOVD 112(RSP), F10
- FMOVD 120(RSP), F11
- FMOVD 128(RSP), F12
- FMOVD 136(RSP), F13
- FMOVD 144(RSP), F14
- FMOVD 152(RSP), F15
+ MOVD 96(RSP), g
+ FMOVD 104(RSP), F8
+ FMOVD 112(RSP), F9
+ FMOVD 120(RSP), F10
+ FMOVD 128(RSP), F11
+ FMOVD 136(RSP), F12
+ FMOVD 144(RSP), F13
+ FMOVD 152(RSP), F14
+ FMOVD 160(RSP), F15
+
RET
TEXT _rt0_arm64_darwin_lib_go(SB),NOSPLIT,$0
diff --git a/src/runtime/rt0_js_wasm.s b/src/runtime/rt0_js_wasm.s
index 2a878d990c..c494b0a34a 100644
--- a/src/runtime/rt0_js_wasm.s
+++ b/src/runtime/rt0_js_wasm.s
@@ -5,45 +5,81 @@
#include "go_asm.h"
#include "textflag.h"
+// The register RUN indicates the current run state of the program.
+// Possible values are:
+#define RUN_STARTING 0
+#define RUN_RUNNING 1
+#define RUN_PAUSED 2
+#define RUN_EXITED 3
+
// _rt0_wasm_js does NOT follow the Go ABI. It has two WebAssembly parameters:
// R0: argc (i32)
// R1: argv (i32)
TEXT _rt0_wasm_js(SB),NOSPLIT,$0
- MOVD $runtime·wasmStack+m0Stack__size(SB), SP
+ Get RUN
+ I32Const $RUN_STARTING
+ I32Eq
+ If
+ MOVD $runtime·wasmStack+m0Stack__size(SB), SP
+
+ Get SP
+ Get R0 // argc
+ I64ExtendUI32
+ I64Store $0
- Get SP
- Get R0 // argc
- I64ExtendUI32
- I64Store $0
+ Get SP
+ Get R1 // argv
+ I64ExtendUI32
+ I64Store $8
- Get SP
- Get R1 // argv
- I64ExtendUI32
- I64Store $8
+ I32Const $runtime·rt0_go(SB)
+ I32Const $16
+ I32ShrU
+ Set PC_F
- I32Const $runtime·rt0_go(SB)
- I32Const $16
- I32ShrU
- Set PC_F
+ I32Const $RUN_RUNNING
+ Set RUN
+ Else
+ Get RUN
+ I32Const $RUN_PAUSED
+ I32Eq
+ If
+ I32Const $RUN_RUNNING
+ Set RUN
+ Else
+ Unreachable
+ End
+ End
-// Call the function for the current PC_F. Repeat until SP=0 indicates program end.
+// Call the function for the current PC_F. Repeat until RUN != 0 indicates pause or exit.
// The WebAssembly stack may unwind, e.g. when switching goroutines.
// The Go stack on the linear memory is then used to jump to the correct functions
// with this loop, without having to restore the full WebAssembly stack.
loop:
Loop
- Get SP
- I32Eqz
- If
- Return
- End
-
Get PC_F
CallIndirect $0
Drop
- Br loop
+ Get RUN
+ I32Const $RUN_RUNNING
+ I32Eq
+ BrIf loop
End
+ Return
+
+TEXT runtime·pause(SB), NOSPLIT, $0
+ I32Const $RUN_PAUSED
+ Set RUN
+ RETUNWIND
+
+TEXT runtime·exit(SB), NOSPLIT, $0-4
+ Call runtime·wasmExit(SB)
+ Drop
+ I32Const $RUN_EXITED
+ Set RUN
+ RETUNWIND
+
TEXT _rt0_wasm_js_lib(SB),NOSPLIT,$0
UNDEF
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 3f936b15b3..4733efba6d 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -33,6 +33,9 @@ func checkGdbEnvironment(t *testing.T) {
if runtime.GOARCH == "ppc64" {
t.Skip("skipping gdb tests on linux/ppc64; see golang.org/issue/17366")
}
+ if runtime.GOARCH == "mips" {
+ t.Skip("skipping gdb tests on linux/mips; see https://golang.org/issue/25939")
+ }
}
if final := os.Getenv("GOROOT_FINAL"); final != "" && runtime.GOROOT() != final {
t.Skip("gdb test can fail with GOROOT_FINAL pending")
diff --git a/src/runtime/runtime-lldb_test.go b/src/runtime/runtime-lldb_test.go
index 9a287052ea..a036fd8480 100644
--- a/src/runtime/runtime-lldb_test.go
+++ b/src/runtime/runtime-lldb_test.go
@@ -10,6 +10,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "regexp"
"runtime"
"strings"
"testing"
@@ -82,8 +83,12 @@ target = debugger.CreateTargetWithFileAndArch("a.exe", None)
if target:
print "Created target"
main_bp = target.BreakpointCreateByLocation("main.go", 10)
- if main_bp:
+ if main_bp.GetNumLocations() != 0:
print "Created breakpoint"
+ else:
+ # This happens if lldb can't read the program's DWARF. See https://golang.org/issue/25925.
+ print "SKIP: no matching locations for breakpoint"
+ exit(1)
process = target.LaunchSimple(None, None, os.getcwd())
if process:
print "Process launched"
@@ -98,7 +103,7 @@ if target:
if state in [lldb.eStateUnloaded, lldb.eStateLaunching, lldb.eStateRunning]:
continue
else:
- print "Timeout launching"
+ print "SKIP: Timeout launching"
break
if state == lldb.eStateStopped:
for t in process.threads:
@@ -172,8 +177,9 @@ func TestLldbPython(t *testing.T) {
got, _ := cmd.CombinedOutput()
if string(got) != expectedLldbOutput {
- if strings.Contains(string(got), "Timeout launching") {
- t.Skip("Timeout launching")
+ skipReason := regexp.MustCompile("SKIP: .*\n").Find(got)
+ if skipReason != nil {
+ t.Skip(string(skipReason))
}
t.Fatalf("Unexpected lldb output:\n%s", got)
}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 1ac0083828..a3193b63c5 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -840,10 +840,13 @@ var (
processorVersionInfo uint32
isIntel bool
lfenceBeforeRdtsc bool
+
+ // Set in runtime.cpuinit.
support_erms bool
support_popcnt bool
support_sse2 bool
support_sse41 bool
+ arm64_support_atomics bool
goarm uint8 // set by cmd/link on arm systems
framepointer_enabled bool // set by cmd/link
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index e40fa9cc1b..648603db35 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -64,8 +64,8 @@ const (
// StackSystem is a number of additional bytes to add
// to each stack below the usual guard area for OS-specific
// purposes like signal handling. Used on Windows, Plan 9,
- // and Darwin/ARM because they do not use a separate stack.
- _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024
+ // and iOS because they do not use a separate stack.
+ _StackSystem = sys.GoosWindows*512*sys.PtrSize + sys.GoosPlan9*512 + sys.GoosDarwin*sys.GoarchArm*1024 + sys.GoosDarwin*sys.GoarchArm64*1024
// The minimum size of stack used by Go code
_StackMin = 2048
@@ -940,7 +940,7 @@ func newstack() {
throw("missing stack in newstack")
}
sp := gp.sched.sp
- if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.Wasm {
+ if sys.ArchFamily == sys.AMD64 || sys.ArchFamily == sys.I386 || sys.ArchFamily == sys.WASM {
// The call to morestack cost a word.
sp -= sys.PtrSize
}
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index d8b5441b31..f0d0815903 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -179,10 +179,135 @@ func walltime() (int64, int32) {
}
func walltime_trampoline()
+//go:nosplit
+//go:cgo_unsafe_args
+func sigaction(sig uint32, new *usigactiont, old *usigactiont) {
+ libcCall(unsafe.Pointer(funcPC(sigaction_trampoline)), unsafe.Pointer(&sig))
+}
+func sigaction_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func sigprocmask(how uint32, new *sigset, old *sigset) {
+ libcCall(unsafe.Pointer(funcPC(sigprocmask_trampoline)), unsafe.Pointer(&how))
+}
+func sigprocmask_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func sigaltstack(new *stackt, old *stackt) {
+ if new != nil && new.ss_flags&_SS_DISABLE != 0 && new.ss_size == 0 {
+ // Despite the fact that Darwin's sigaltstack man page says it ignores the size
+ // when SS_DISABLE is set, it doesn't. sigaltstack returns ENOMEM
+ // if we don't give it a reasonable size.
+ // ref: http://lists.llvm.org/pipermail/llvm-commits/Week-of-Mon-20140421/214296.html
+ new.ss_size = 32768
+ }
+ libcCall(unsafe.Pointer(funcPC(sigaltstack_trampoline)), unsafe.Pointer(&new))
+}
+func sigaltstack_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func raiseproc(sig uint32) {
+ libcCall(unsafe.Pointer(funcPC(raiseproc_trampoline)), unsafe.Pointer(&sig))
+}
+func raiseproc_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func setitimer(mode int32, new, old *itimerval) {
+ libcCall(unsafe.Pointer(funcPC(setitimer_trampoline)), unsafe.Pointer(&mode))
+}
+func setitimer_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func sysctl(mib *uint32, miblen uint32, out *byte, size *uintptr, dst *byte, ndst uintptr) int32 {
+ return libcCall(unsafe.Pointer(funcPC(sysctl_trampoline)), unsafe.Pointer(&mib))
+}
+func sysctl_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func fcntl(fd, cmd, arg int32) int32 {
+ return libcCall(unsafe.Pointer(funcPC(fcntl_trampoline)), unsafe.Pointer(&fd))
+}
+func fcntl_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func kqueue() int32 {
+ v := libcCall(unsafe.Pointer(funcPC(kqueue_trampoline)), nil)
+ return v
+}
+func kqueue_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32 {
+ return libcCall(unsafe.Pointer(funcPC(kevent_trampoline)), unsafe.Pointer(&kq))
+}
+func kevent_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_mutex_init(m *pthreadmutex, attr *pthreadmutexattr) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_mutex_init_trampoline)), unsafe.Pointer(&m))
+}
+func pthread_mutex_init_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_mutex_lock(m *pthreadmutex) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_mutex_lock_trampoline)), unsafe.Pointer(&m))
+}
+func pthread_mutex_lock_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_mutex_unlock(m *pthreadmutex) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_mutex_unlock_trampoline)), unsafe.Pointer(&m))
+}
+func pthread_mutex_unlock_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_cond_init(c *pthreadcond, attr *pthreadcondattr) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_cond_init_trampoline)), unsafe.Pointer(&c))
+}
+func pthread_cond_init_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_cond_wait(c *pthreadcond, m *pthreadmutex) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_cond_wait_trampoline)), unsafe.Pointer(&c))
+}
+func pthread_cond_wait_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_cond_timedwait_relative_np(c *pthreadcond, m *pthreadmutex, t *timespec) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_cond_timedwait_relative_np_trampoline)), unsafe.Pointer(&c))
+}
+func pthread_cond_timedwait_relative_np_trampoline()
+
+//go:nosplit
+//go:cgo_unsafe_args
+func pthread_cond_signal(c *pthreadcond) int32 {
+ return libcCall(unsafe.Pointer(funcPC(pthread_cond_signal_trampoline)), unsafe.Pointer(&c))
+}
+func pthread_cond_signal_trampoline()
+
// Not used on Darwin, but must be defined.
func exitThread(wait *uint32) {
}
+//go:nosplit
+func closeonexec(fd int32) {
+ fcntl(fd, _F_SETFD, _FD_CLOEXEC)
+}
+
// Tell the linker that the libc_* functions are to be found
// in a system library, with the libc_ prefix missing.
@@ -207,6 +332,24 @@ func exitThread(wait *uint32) {
//go:cgo_import_dynamic libc_mach_timebase_info mach_timebase_info "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_mach_absolute_time mach_absolute_time "/usr/lib/libSystem.B.dylib"
//go:cgo_import_dynamic libc_gettimeofday gettimeofday "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_sigaction sigaction "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_sigmask pthread_sigmask "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_sigaltstack sigaltstack "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_getpid getpid "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_kill kill "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_setitimer setitimer "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_sysctl sysctl "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_fcntl fcntl "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_kqueue kqueue "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_kevent kevent "/usr/lib/libSystem.B.dylib"
+
+//go:cgo_import_dynamic libc_pthread_mutex_init pthread_mutex_init "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_mutex_lock pthread_mutex_lock "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_mutex_unlock pthread_mutex_unlock "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_cond_init pthread_cond_init "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_cond_wait pthread_cond_wait "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_cond_timedwait_relative_np pthread_cond_timedwait_relative_np "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic libc_pthread_cond_signal pthread_cond_signal "/usr/lib/libSystem.B.dylib"
// Magic incantation to get libSystem actually dynamically linked.
// TODO: Why does the code require this? See cmd/compile/internal/ld/go.go:210
diff --git a/src/runtime/sys_darwin_386.s b/src/runtime/sys_darwin_386.s
index 5b29dfe604..09f12283a1 100644
--- a/src/runtime/sys_darwin_386.s
+++ b/src/runtime/sys_darwin_386.s
@@ -3,8 +3,8 @@
// license that can be found in the LICENSE file.
// System calls and other sys.stuff for 386, Darwin
-// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
-// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+// System calls are implemented in libSystem, this file contains
+// trampolines that convert from Go to C calling convention.
#include "go_asm.h"
#include "go_tls.h"
@@ -84,17 +84,6 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0
POPL BP
RET
-TEXT runtime·raiseproc(SB),NOSPLIT,$16
- MOVL $20, AX // getpid
- INT $0x80
- MOVL AX, 4(SP) // pid
- MOVL sig+0(FP), AX
- MOVL AX, 8(SP) // signal
- MOVL $1, 12(SP) // posix
- MOVL $37, AX // kill
- INT $0x80
- RET
-
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHL BP
MOVL SP, BP
@@ -161,9 +150,20 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
POPL BP
RET
-TEXT runtime·setitimer(SB),NOSPLIT,$0
- MOVL $83, AX
- INT $0x80
+TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 mode
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 new
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 old
+ MOVL AX, 8(SP)
+ CALL libc_setitimer(SB)
+ MOVL BP, SP
+ POPL BP
RET
TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
@@ -211,18 +211,73 @@ initialized:
POPL BP
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL $329, AX // pthread_sigmask (on OS X, sigprocmask==entire process)
- INT $0x80
- JAE 2(PC)
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 sig
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 new
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 old
+ MOVL AX, 8(SP)
+ CALL libc_sigaction(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 how
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 new
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 old
+ MOVL AX, 8(SP)
+ CALL libc_pthread_sigmask(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0
- MOVL $46, AX
- INT $0x80
- JAE 2(PC)
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 new
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 old
+ MOVL AX, 4(SP)
+ CALL libc_sigaltstack(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ CALL libc_getpid(SB)
+ MOVL AX, 0(SP) // arg 1 pid
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX
+ MOVL AX, 4(SP) // arg 2 signal
+ CALL libc_kill(SB)
+ MOVL BP, SP
+ POPL BP
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
@@ -243,38 +298,32 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
RET
// Sigtramp's job is to call the actual signal handler.
-// It is called with the following arguments on the stack:
-// 0(SP) "return address" - ignored
-// 4(SP) actual handler
-// 8(SP) siginfo style
-// 12(SP) signal number
-// 16(SP) siginfo
-// 20(SP) context
-TEXT runtime·sigtramp(SB),NOSPLIT,$20
- MOVL sig+8(FP), BX
- MOVL BX, 0(SP)
- MOVL info+12(FP), BX
- MOVL BX, 4(SP)
- MOVL ctx+16(FP), BX
- MOVL BX, 8(SP)
+// It is called with the C calling convention, and calls out
+// to sigtrampgo with the Go calling convention.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ SUBL $28, SP
+
+ // Save callee-save registers.
+ MOVL BP, 12(SP)
+ MOVL BX, 16(SP)
+ MOVL SI, 20(SP)
+ MOVL DI, 24(SP)
+
+ MOVL 32(SP), AX
+ MOVL AX, 0(SP) // arg 1 signal number
+ MOVL 36(SP), AX
+ MOVL AX, 4(SP) // arg 2 siginfo
+ MOVL 40(SP), AX
+ MOVL AX, 8(SP) // arg 3 ctxt
CALL runtime·sigtrampgo(SB)
- // call sigreturn
- MOVL ctx+16(FP), CX
- MOVL infostyle+4(FP), BX
- MOVL $0, 0(SP) // "caller PC" - ignored
- MOVL CX, 4(SP)
- MOVL BX, 8(SP)
- MOVL $184, AX // sigreturn(ucontext, infostyle)
- INT $0x80
- MOVL $0xf1, 0xf1 // crash
- RET
+ // Restore callee-save registers.
+ MOVL 12(SP), BP
+ MOVL 16(SP), BX
+ MOVL 20(SP), SI
+ MOVL 24(SP), DI
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
- MOVL $53, AX
- INT $0x80
- JAE 2(PC)
- MOVL $0xf1, 0xf1 // crash
+ ADDL $28, SP
RET
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
@@ -289,117 +338,84 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
POPL BP
RET
-// Invoke Mach system call.
-// Assumes system call number in AX,
-// caller PC on stack, caller's caller PC next,
-// and then the system call arguments.
-//
-// Can be used for BSD too, but we don't,
-// because if you use this interface the BSD
-// system call numbers need an extra field
-// in the high 16 bits that seems to be the
-// argument count in bytes but is not always.
-// INT $0x80 works fine for those.
-TEXT runtime·sysenter(SB),NOSPLIT,$0
- POPL DX
- MOVL SP, CX
- SYSENTER
- // returns to DX with SP set to CX
-
-TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
- MOVL $-31, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+28(FP)
- RET
-
-TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
- MOVL $-26, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+0(FP)
- RET
-
-TEXT runtime·mach_task_self(SB),NOSPLIT,$0
- MOVL $-28, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+0(FP)
- RET
-
-// Mach provides trap versions of the semaphore ops,
-// instead of requiring the use of RPC.
-
-// func mach_semaphore_wait(sema uint32) int32
-TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
- MOVL $-36, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+4(FP)
- RET
-
-// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
-TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
- MOVL $-38, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+12(FP)
- RET
-
-// func mach_semaphore_signal(sema uint32) int32
-TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
- MOVL $-33, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+4(FP)
- RET
-
-// func mach_semaphore_signal_all(sema uint32) int32
-TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
- MOVL $-34, AX
- CALL runtime·sysenter(SB)
- MOVL AX, ret+4(FP)
- RET
-
// func setldt(entry int, address int, limit int)
TEXT runtime·setldt(SB),NOSPLIT,$32
// Nothing to do on Darwin, pthread already set thread-local storage up.
RET
-TEXT runtime·sysctl(SB),NOSPLIT,$0
- MOVL $202, AX
- INT $0x80
- JAE 4(PC)
- NEGL AX
- MOVL AX, ret+24(FP)
- RET
- MOVL $0, AX
- MOVL AX, ret+24(FP)
+TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 mib
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 miblen
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 out
+ MOVL AX, 8(SP)
+ MOVL 12(CX), AX // arg 4 size
+ MOVL AX, 12(SP)
+ MOVL 16(CX), AX // arg 5 dst
+ MOVL AX, 16(SP)
+ MOVL 20(CX), AX // arg 6 ndst
+ MOVL AX, 20(SP)
+ CALL libc_sysctl(SB)
+ MOVL BP, SP
+ POPL BP
RET
-// func kqueue() int32
-TEXT runtime·kqueue(SB),NOSPLIT,$0
- MOVL $362, AX
- INT $0x80
- JAE 2(PC)
- NEGL AX
- MOVL AX, ret+0(FP)
+TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ CALL libc_kqueue(SB)
+ MOVL BP, SP
+ POPL BP
RET
-// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
-TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL $363, AX
- INT $0x80
- JAE 2(PC)
- NEGL AX
- MOVL AX, ret+24(FP)
+TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 kq
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 ch
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 nch
+ MOVL AX, 8(SP)
+ MOVL 12(CX), AX // arg 4 ev
+ MOVL AX, 12(SP)
+ MOVL 16(CX), AX // arg 5 nev
+ MOVL AX, 16(SP)
+ MOVL 20(CX), AX // arg 6 ts
+ MOVL AX, 20(SP)
+ CALL libc_kevent(SB)
+ CMPL AX, $-1
+ JNE ok
+ CALL libc_error(SB)
+ MOVL (AX), AX // errno
+ NEGL AX // caller wants it as a negative error code
+ok:
+ MOVL BP, SP
+ POPL BP
RET
-// func closeonexec(fd int32)
-TEXT runtime·closeonexec(SB),NOSPLIT,$32
- MOVL $92, AX // fcntl
- // 0(SP) is where the caller PC would be; kernel skips it
- MOVL fd+0(FP), BX
- MOVL BX, 4(SP) // fd
- MOVL $2, 8(SP) // F_SETFD
- MOVL $1, 12(SP) // FD_CLOEXEC
- INT $0x80
- JAE 2(PC)
- NEGL AX
+TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 fd
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 cmd
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 arg
+ MOVL AX, 8(SP)
+ CALL libc_fcntl(SB)
+ MOVL BP, SP
+ POPL BP
RET
// mstart_stub is the first function executed on a new thread started by pthread_create.
@@ -409,8 +425,15 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
// The value at SP+4 points to the m.
// We are already on m's g0 stack.
+ // Save callee-save registers.
+ SUBL $16, SP
+ MOVL BP, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL SI, 8(SP)
+ MOVL DI, 12(SP)
+
MOVL SP, AX // hide argument read from vet (vet thinks this function is using the Go calling convention)
- MOVL 4(AX), DI // m
+ MOVL 20(AX), DI // m
MOVL m_g0(DI), DX // g
// Initialize TLS entry.
@@ -422,10 +445,18 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
CALL runtime·mstart(SB)
+ // Restore callee-save registers.
+ MOVL 0(SP), BP
+ MOVL 4(SP), BX
+ MOVL 8(SP), SI
+ MOVL 12(SP), DI
+
// Go is all done with this OS thread.
// Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX
+
+ ADDL $16, SP
RET
TEXT runtime·pthread_attr_init_trampoline(SB),NOSPLIT,$0
@@ -497,3 +528,97 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
MOVL BP, SP
POPL BP
RET
+
+TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 mutex
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 attr
+ MOVL AX, 4(SP)
+ CALL libc_pthread_mutex_init(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 mutex
+ MOVL AX, 0(SP)
+ CALL libc_pthread_mutex_lock(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 mutex
+ MOVL AX, 0(SP)
+ CALL libc_pthread_mutex_unlock(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 cond
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 attr
+ MOVL AX, 4(SP)
+ CALL libc_pthread_cond_init(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 cond
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 mutex
+ MOVL AX, 4(SP)
+ CALL libc_pthread_cond_wait(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $24, SP
+ MOVL 32(SP), CX
+ MOVL 0(CX), AX // arg 1 cond
+ MOVL AX, 0(SP)
+ MOVL 4(CX), AX // arg 2 mutex
+ MOVL AX, 4(SP)
+ MOVL 8(CX), AX // arg 3 timeout
+ MOVL AX, 8(SP)
+ CALL libc_pthread_cond_timedwait_relative_np(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
+
+TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
+ PUSHL BP
+ MOVL SP, BP
+ SUBL $8, SP
+ MOVL 16(SP), CX
+ MOVL 0(CX), AX // arg 1 cond
+ MOVL AX, 0(SP)
+ CALL libc_pthread_cond_signal(SB)
+ MOVL BP, SP
+ POPL BP
+ RET
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index 320d56499a..142933585d 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -2,14 +2,9 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-//
// System calls and other sys.stuff for AMD64, Darwin
-// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
-// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
-//
-// The low 24 bits are the system call number.
-// The high 8 bits specify the kind of system call: 1=Mach, 2=BSD, 3=Machine-Dependent.
-//
+// System calls are implemented in libSystem, this file contains
+// trampolines that convert from Go to C calling convention.
#include "go_asm.h"
#include "go_tls.h"
@@ -63,22 +58,14 @@ TEXT runtime·write_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
-TEXT runtime·raiseproc(SB),NOSPLIT,$24
- MOVL $(0x2000000+20), AX // getpid
- SYSCALL
- MOVQ AX, DI // arg 1 - pid
- MOVL sig+0(FP), SI // arg 2 - signal
- MOVL $1, DX // arg 3 - posix
- MOVL $(0x2000000+37), AX // kill
- SYSCALL
- RET
-
-TEXT runtime·setitimer(SB), NOSPLIT, $0
- MOVL mode+0(FP), DI
- MOVQ new+8(FP), SI
- MOVQ old+16(FP), DX
- MOVL $(0x2000000+83), AX // syscall entry
- SYSCALL
+TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 new
+ MOVQ 16(DI), DX // arg 3 old
+ MOVL 0(DI), DI // arg 1 which
+ CALL libc_setitimer(SB)
+ POPQ BP
RET
TEXT runtime·madvise_trampoline(SB), NOSPLIT, $0
@@ -132,26 +119,53 @@ TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVL how+0(FP), DI
- MOVQ new+8(FP), SI
- MOVQ old+16(FP), DX
- MOVL $(0x2000000+329), AX // pthread_sigmask (on OS X, sigprocmask==entire process)
- SYSCALL
- JCC 2(PC)
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 new
+ MOVQ 16(DI), DX // arg 3 old
+ MOVL 0(DI), DI // arg 1 sig
+ CALL libc_sigaction(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ POPQ BP
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0-24
- MOVL mode+0(FP), DI // arg 1 sig
- MOVQ new+8(FP), SI // arg 2 act
- MOVQ old+16(FP), DX // arg 3 oact
- MOVQ old+16(FP), CX // arg 3 oact
- MOVQ old+16(FP), R10 // arg 3 oact
- MOVL $(0x2000000+46), AX // syscall entry
- SYSCALL
- JCC 2(PC)
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 new
+ MOVQ 16(DI), DX // arg 3 old
+ MOVL 0(DI), DI // arg 1 how
+ CALL libc_pthread_sigmask(SB)
+ TESTL AX, AX
+ JEQ 2(PC)
MOVL $0xf1, 0xf1 // crash
+ POPQ BP
+ RET
+
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 old
+ MOVQ 0(DI), DI // arg 1 new
+ CALL libc_sigaltstack(SB)
+ TESTQ AX, AX
+ JEQ 2(PC)
+ MOVL $0xf1, 0xf1 // crash
+ POPQ BP
+ RET
+
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVL 0(DI), BX // signal
+ CALL libc_getpid(SB)
+ MOVL AX, DI // arg 1 pid
+ MOVL BX, SI // arg 2 signal
+ CALL libc_kill(SB)
+ POPQ BP
RET
TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
@@ -167,21 +181,39 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
POPQ BP
RET
-TEXT runtime·sigtramp(SB),NOSPLIT,$40
- MOVL SI, 24(SP) // save infostyle for sigreturn below
- MOVQ R8, 32(SP) // save ctx
- MOVL DX, 0(SP) // sig
- MOVQ CX, 8(SP) // info
- MOVQ R8, 16(SP) // ctx
- MOVQ $runtime·sigtrampgo(SB), AX
- CALL AX
- MOVQ 32(SP), DI // ctx
- MOVL 24(SP), SI // infostyle
- MOVL $(0x2000000+184), AX
- SYSCALL
- INT $3 // not reached
-
+// This is the function registered during sigaction and is invoked when
+// a signal is received. It just redirects to the Go function sigtrampgo.
+TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // This runs on the signal stack, so we have lots of stack available.
+ // We allocate our own stack space, because if we tell the linker
+ // how much we're using, the NOSPLIT check fails.
+ PUSHQ BP
+ MOVQ SP, BP
+ SUBQ $64, SP
+
+ // Save callee-save registers.
+ MOVQ BX, 24(SP)
+ MOVQ R12, 32(SP)
+ MOVQ R13, 40(SP)
+ MOVQ R14, 48(SP)
+ MOVQ R15, 56(SP)
+
+ // Call into the Go signal handler
+ MOVL DI, 0(SP) // sig
+ MOVQ SI, 8(SP) // info
+ MOVQ DX, 16(SP) // ctx
+ CALL runtime·sigtrampgo(SB)
+
+ // Restore callee-save registers.
+ MOVQ 24(SP), BX
+ MOVQ 32(SP), R12
+ MOVQ 40(SP), R13
+ MOVQ 48(SP), R14
+ MOVQ 56(SP), R15
+ MOVQ BP, SP
+ POPQ BP
+ RET
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
PUSHQ BP // make a frame; keep stack aligned
@@ -218,15 +250,6 @@ TEXT runtime·munmap_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
- MOVQ new+0(FP), DI
- MOVQ old+8(FP), SI
- MOVQ $(0x2000000+53), AX
- SYSCALL
- JCC 2(PC)
- MOVL $0xf1, 0xf1 // crash
- RET
-
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
PUSHQ BP
MOVQ SP, BP
@@ -235,134 +258,57 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
POPQ BP
RET
-// Mach system calls use 0x1000000 instead of the BSD's 0x2000000.
-
-// func mach_msg_trap(h unsafe.Pointer, op int32, send_size, rcv_size, rcv_name, timeout, notify uint32) int32
-TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
- MOVQ h+0(FP), DI
- MOVL op+8(FP), SI
- MOVL send_size+12(FP), DX
- MOVL rcv_size+16(FP), R10
- MOVL rcv_name+20(FP), R8
- MOVL timeout+24(FP), R9
- MOVL notify+28(FP), R11
- PUSHQ R11 // seventh arg, on stack
- MOVL $(0x1000000+31), AX // mach_msg_trap
- SYSCALL
- POPQ R11
- MOVL AX, ret+32(FP)
- RET
-
-TEXT runtime·mach_task_self(SB),NOSPLIT,$0
- MOVL $(0x1000000+28), AX // task_self_trap
- SYSCALL
- MOVL AX, ret+0(FP)
- RET
-
-TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
- MOVL $(0x1000000+27), AX // thread_self_trap
- SYSCALL
- MOVL AX, ret+0(FP)
- RET
-
-TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
- MOVL $(0x1000000+26), AX // mach_reply_port
- SYSCALL
- MOVL AX, ret+0(FP)
- RET
-
-// Mach provides trap versions of the semaphore ops,
-// instead of requiring the use of RPC.
-
-// func mach_semaphore_wait(sema uint32) int32
-TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
- MOVL sema+0(FP), DI
- MOVL $(0x1000000+36), AX // semaphore_wait_trap
- SYSCALL
- MOVL AX, ret+8(FP)
- RET
-
-// func mach_semaphore_timedwait(sema, sec, nsec uint32) int32
-TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
- MOVL sema+0(FP), DI
- MOVL sec+4(FP), SI
- MOVL nsec+8(FP), DX
- MOVL $(0x1000000+38), AX // semaphore_timedwait_trap
- SYSCALL
- MOVL AX, ret+16(FP)
+TEXT runtime·settls(SB),NOSPLIT,$32
+ // Nothing to do on Darwin, pthread already set thread-local storage up.
RET
-// func mach_semaphore_signal(sema uint32) int32
-TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
- MOVL sema+0(FP), DI
- MOVL $(0x1000000+33), AX // semaphore_signal_trap
- SYSCALL
- MOVL AX, ret+8(FP)
+TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVL 8(DI), SI // arg 2 miblen
+ MOVQ 16(DI), DX // arg 3 out
+ MOVQ 24(DI), CX // arg 4 size
+ MOVQ 32(DI), R8 // arg 5 dst
+ MOVQ 40(DI), R9 // arg 6 ndst
+ MOVQ 0(DI), DI // arg 1 mib
+ CALL libc_sysctl(SB)
+ POPQ BP
RET
-// func mach_semaphore_signal_all(sema uint32) int32
-TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
- MOVL sema+0(FP), DI
- MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
- SYSCALL
- MOVL AX, ret+8(FP)
+TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ CALL libc_kqueue(SB)
+ POPQ BP
RET
-TEXT runtime·settls(SB),NOSPLIT,$32
- // Nothing to do on Darwin, pthread already set thread-local storage up.
+TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 keventt
+ MOVL 16(DI), DX // arg 3 nch
+ MOVQ 24(DI), CX // arg 4 ev
+ MOVL 32(DI), R8 // arg 5 nev
+ MOVQ 40(DI), R9 // arg 6 ts
+ MOVL 0(DI), DI // arg 1 kq
+ CALL libc_kevent(SB)
+ CMPQ AX, $-1
+ JNE ok
+ CALL libc_error(SB)
+ MOVQ (AX), AX // errno
+ NEGQ AX // caller wants it as a negative error code
+ok:
+ POPQ BP
RET
-TEXT runtime·sysctl(SB),NOSPLIT,$0
- MOVQ mib+0(FP), DI
- MOVL miblen+8(FP), SI
- MOVQ out+16(FP), DX
- MOVQ size+24(FP), R10
- MOVQ dst+32(FP), R8
- MOVQ ndst+40(FP), R9
- MOVL $(0x2000000+202), AX // syscall entry
- SYSCALL
- JCC 4(PC)
- NEGQ AX
- MOVL AX, ret+48(FP)
- RET
- MOVL $0, AX
- MOVL AX, ret+48(FP)
- RET
-
-// func kqueue() int32
-TEXT runtime·kqueue(SB),NOSPLIT,$0
- MOVQ $0, DI
- MOVQ $0, SI
- MOVQ $0, DX
- MOVL $(0x2000000+362), AX
- SYSCALL
- JCC 2(PC)
- NEGQ AX
- MOVL AX, ret+0(FP)
- RET
-
-// func kevent(kq int32, ch *keventt, nch int32, ev *keventt, nev int32, ts *timespec) int32
-TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVL kq+0(FP), DI
- MOVQ ch+8(FP), SI
- MOVL nch+16(FP), DX
- MOVQ ev+24(FP), R10
- MOVL nev+32(FP), R8
- MOVQ ts+40(FP), R9
- MOVL $(0x2000000+363), AX
- SYSCALL
- JCC 2(PC)
- NEGQ AX
- MOVL AX, ret+48(FP)
- RET
-
-// func closeonexec(fd int32)
-TEXT runtime·closeonexec(SB),NOSPLIT,$0
- MOVL fd+0(FP), DI // fd
- MOVQ $2, SI // F_SETFD
- MOVQ $1, DX // FD_CLOEXEC
- MOVL $(0x2000000+92), AX // fcntl
- SYSCALL
+TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVL 4(DI), SI // arg 2 cmd
+ MOVL 8(DI), DX // arg 3 arg
+ MOVL 0(DI), DI // arg 1 fd
+ CALL libc_fcntl(SB)
+ POPQ BP
RET
// mstart_stub is the first function executed on a new thread started by pthread_create.
@@ -372,6 +318,14 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
// DI points to the m.
// We are already on m's g0 stack.
+ // Save callee-save registers.
+ SUBQ $40, SP
+ MOVQ BX, 0(SP)
+ MOVQ R12, 8(SP)
+ MOVQ R13, 16(SP)
+ MOVQ R14, 24(SP)
+ MOVQ R15, 32(SP)
+
MOVQ m_g0(DI), DX // g
// Initialize TLS entry.
@@ -383,10 +337,19 @@ TEXT runtime·mstart_stub(SB),NOSPLIT,$0
CALL runtime·mstart(SB)
+ // Restore callee-save registers.
+ MOVQ 0(SP), BX
+ MOVQ 8(SP), R12
+ MOVQ 16(SP), R13
+ MOVQ 24(SP), R14
+ MOVQ 32(SP), R15
+
// Go is all done with this OS thread.
// Tell pthread everything is ok (we never join with this thread, so
// the value here doesn't really matter).
XORL AX, AX
+
+ ADDQ $40, SP
RET
// These trampolines help convert from Go calling convention to C calling convention.
@@ -440,3 +403,64 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
CALL libc_raise(SB)
POPQ BP
RET
+
+TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 attr
+ MOVQ 0(DI), DI // arg 1 mutex
+ CALL libc_pthread_mutex_init(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 0(DI), DI // arg 1 mutex
+ CALL libc_pthread_mutex_lock(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 0(DI), DI // arg 1 mutex
+ CALL libc_pthread_mutex_unlock(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 attr
+ MOVQ 0(DI), DI // arg 1 cond
+ CALL libc_pthread_cond_init(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 mutex
+ MOVQ 0(DI), DI // arg 1 cond
+ CALL libc_pthread_cond_wait(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 8(DI), SI // arg 2 mutex
+ MOVQ 16(DI), DX // arg 3 timeout
+ MOVQ 0(DI), DI // arg 1 cond
+ CALL libc_pthread_cond_timedwait_relative_np(SB)
+ POPQ BP
+ RET
+
+TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ MOVQ 0(DI), DI // arg 1 cond
+ CALL libc_pthread_cond_signal(SB)
+ POPQ BP
+ RET
diff --git a/src/runtime/sys_darwin_arm.s b/src/runtime/sys_darwin_arm.s
index a940d95732..9b5c667f45 100644
--- a/src/runtime/sys_darwin_arm.s
+++ b/src/runtime/sys_darwin_arm.s
@@ -3,26 +3,13 @@
// license that can be found in the LICENSE file.
// System calls and other sys.stuff for ARM, Darwin
-// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
-// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+// System calls are implemented in libSystem, this file contains
+// trampolines that convert from Go to C calling convention.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
-// Copied from /usr/include/sys/syscall.h
-#define SYS_gettimeofday 116
-#define SYS_kill 37
-#define SYS_getpid 20
-#define SYS_pthread_sigmask 329
-#define SYS_setitimer 83
-#define SYS___sysctl 202
-#define SYS_sigaction 46
-#define SYS_sigreturn 184
-#define SYS_kqueue 362
-#define SYS_kevent 363
-#define SYS_fcntl 92
-
TEXT notok<>(SB),NOSPLIT,$0
MOVW $0, R8
MOVW R8, (R8)
@@ -61,14 +48,12 @@ TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
MOVW $1002, R1
MOVW R0, (R1) // fail hard
-TEXT runtime·raiseproc(SB),NOSPLIT,$24
- MOVW $SYS_getpid, R12
- SWI $0x80
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ MOVW 0(R0), R8 // signal
+ BL libc_getpid(SB)
// arg 1 pid already in R0 from getpid
- MOVW sig+0(FP), R1 // arg 2 - signal
- MOVW $1, R2 // arg 3 - posix
- MOVW $SYS_kill, R12
- SWI $0x80
+ MOVW R8, R1 // arg 2 signal
+ BL libc_kill(SB)
RET
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
@@ -116,12 +101,11 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
BL.EQ notok<>(SB)
RET
-TEXT runtime·setitimer(SB),NOSPLIT,$0
- MOVW mode+0(FP), R0
- MOVW new+4(FP), R1
- MOVW old+8(FP), R2
- MOVW $SYS_setitimer, R12
- SWI $0x80
+TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 new
+ MOVW 8(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 which
+ BL libc_setitimer(SB)
RET
TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
@@ -174,91 +158,89 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-16
MOVW R4, R13
RET
-// Sigtramp's job is to call the actual signal handler.
-// It is called with the following arguments on the stack:
-// LR "return address" - ignored
-// R0 actual handler
-// R1 siginfo style - ignored
-// R2 signal number
-// R3 siginfo
-// -4(FP) context, beware that 0(FP) is the saved LR
TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ SUB $36, R13
+
+ MOVW R4, 12(R13)
+ MOVW R5, 16(R13)
+ MOVW R6, 20(R13)
+ MOVW R7, 24(R13)
+ MOVW R8, 28(R13)
+ MOVW R11, 32(R13)
+
+ // Save arguments.
+ MOVW R0, 4(R13) // sig
+ MOVW R1, 8(R13) // info
+ MOVW R2, 12(R13) // ctx
+
// this might be called in external code context,
// where g is not set.
- // first save R0, because runtime·load_g will clobber it
- MOVM.DB.W [R0], (R13)
MOVB runtime·iscgo(SB), R0
CMP $0, R0
BL.NE runtime·load_g(SB)
- CMP $0, g
- BNE cont
- // fake function call stack frame for badsignal
- // we only need to pass R2 (signal number), but
- // badsignal will expect R2 at 4(R13), so we also
- // push R1 onto stack. turns out we do need R1
- // to do sigreturn.
- MOVM.DB.W [R1,R2], (R13)
- MOVW $runtime·badsignal(SB), R11
- BL (R11)
- MOVM.IA.W [R1], (R13) // saved infostype
- ADD $(4+4), R13 // +4: also need to remove the pushed R0.
- MOVW ucontext-4(FP), R0 // load ucontext
- B ret
-
-cont:
- // Restore R0
- MOVM.IA.W (R13), [R0]
+ MOVW R13, R6
+ CMP $0, g
+ BEQ nog
- // NOTE: some Darwin/ARM kernels always use the main stack to run the
- // signal handler. We need to switch to gsignal ourselves.
+ // iOS always use the main stack to run the signal handler.
+ // We need to switch to gsignal ourselves.
MOVW g_m(g), R11
MOVW m_gsignal(R11), R5
MOVW (g_stack+stack_hi)(R5), R6
- SUB $28, R6
- // copy arguments for call to sighandler
- MOVW R2, 4(R6) // signal num
- MOVW R3, 8(R6) // signal info
- MOVW g, 16(R6) // old_g
- MOVW context-4(FP), R4
- MOVW R4, 12(R6) // context
+nog:
+ // Restore arguments.
+ MOVW 4(R13), R0
+ MOVW 8(R13), R1
+ MOVW 12(R13), R2
- // Backup ucontext and infostyle
- MOVW R4, 20(R6)
- MOVW R1, 24(R6)
+ // Reserve space for args and the stack pointer on the
+ // gsignal stack.
+ SUB $24, R6
+ // Save stack pointer.
+ MOVW R13, R4
+ MOVW R4, 16(R6)
+ // Switch to gsignal stack.
+ MOVW R6, R13
- // switch stack and g
- MOVW R6, R13 // sigtramp is not re-entrant, so no need to back up R13.
- MOVW R5, g
+ // Call sigtrampgo
+ MOVW R0, 4(R13)
+ MOVW R1, 8(R13)
+ MOVW R2, 12(R13)
+ BL runtime·sigtrampgo(SB)
- BL (R0)
+ // Switch to old stack.
+ MOVW 16(R13), R5
+ MOVW R5, R13
- // call sigreturn
- MOVW 20(R13), R0 // saved ucontext
- MOVW 24(R13), R1 // saved infostyle
-ret:
- MOVW $SYS_sigreturn, R12 // sigreturn(ucontext, infostyle)
- SWI $0x80
+ // Restore callee-save registers.
+ MOVW 12(R13), R4
+ MOVW 16(R13), R5
+ MOVW 20(R13), R6
+ MOVW 24(R13), R7
+ MOVW 28(R13), R8
+ MOVW 32(R13), R11
- // if sigreturn fails, we can do nothing but exit
- B runtime·exit(SB)
+ ADD $36, R13
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW how+0(FP), R0
- MOVW new+4(FP), R1
- MOVW old+8(FP), R2
- MOVW $SYS_pthread_sigmask, R12
- SWI $0x80
- BL.CS notok<>(SB)
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0
- MOVW mode+0(FP), R0
- MOVW new+4(FP), R1
- MOVW old+8(FP), R2
- MOVW $SYS_sigaction, R12
- SWI $0x80
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 new
+ MOVW 8(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 how
+ BL libc_pthread_sigmask(SB)
+ CMP $0, R0
+ BL.NE notok<>(SB)
+ RET
+
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 new
+ MOVW 8(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 how
+ BL libc_sigaction(SB)
RET
TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
@@ -269,128 +251,58 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
B runtime·armPublicationBarrier(SB)
-TEXT runtime·sysctl(SB),NOSPLIT,$0
- MOVW mib+0(FP), R0
- MOVW miblen+4(FP), R1
- MOVW out+8(FP), R2
- MOVW size+12(FP), R3
- MOVW dst+16(FP), R4
- MOVW ndst+20(FP), R5
- MOVW $SYS___sysctl, R12 // syscall entry
- SWI $0x80
- BCC sysctl_ret
- RSB $0, R0, R0
- MOVW R0, ret+24(FP)
- RET
-sysctl_ret:
- MOVW $0, R0
- MOVW R0, ret+24(FP)
- RET
-
-// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
-TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
- MOVW h+0(FP), R0
- MOVW op+4(FP), R1
- MOVW send_size+8(FP), R2
- MOVW rcv_size+12(FP), R3
- MOVW rcv_name+16(FP), R4
- MOVW timeout+20(FP), R5
- MOVW notify+24(FP), R6
- MVN $30, R12
- SWI $0x80
- MOVW R0, ret+28(FP)
- RET
-
-TEXT runtime·mach_task_self(SB),NOSPLIT,$0
- MVN $27, R12 // task_self_trap
- SWI $0x80
- MOVW R0, ret+0(FP)
- RET
-
-TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
- MVN $26, R12 // thread_self_trap
- SWI $0x80
- MOVW R0, ret+0(FP)
- RET
-
-TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
- MVN $25, R12 // mach_reply_port
- SWI $0x80
- MOVW R0, ret+0(FP)
- RET
-
-// Mach provides trap versions of the semaphore ops,
-// instead of requiring the use of RPC.
-
-// uint32 mach_semaphore_wait(uint32)
-TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MVN $35, R12 // semaphore_wait_trap
- SWI $0x80
- MOVW R0, ret+4(FP)
- RET
-
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
-TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MOVW sec+4(FP), R1
- MOVW nsec+8(FP), R2
- MVN $37, R12 // semaphore_timedwait_trap
- SWI $0x80
- MOVW R0, ret+12(FP)
+TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 miblen
+ MOVW 8(R0), R2 // arg 3 out
+ MOVW 12(R0), R3 // arg 4 size
+ MOVW 16(R0), R4 // arg 5 dst
+ MOVW 20(R0), R5 // arg 6 ndst
+ MOVW 0(R0), R0 // arg 1 mib
+ // Only R0-R3 are used for arguments, the rest
+ // go on the stack.
+ MOVM.DB.W [R4-R5], (R13)
+ BL libc_sysctl(SB)
+ ADD $(2*4), R13
RET
-// uint32 mach_semaphore_signal(uint32)
-TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MVN $32, R12 // semaphore_signal_trap
- SWI $0x80
- MOVW R0, ret+4(FP)
+TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
+ BL libc_kqueue(SB)
RET
-// uint32 mach_semaphore_signal_all(uint32)
-TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MVN $33, R12 // semaphore_signal_all_trap
- SWI $0x80
- MOVW R0, ret+4(FP)
+// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
+TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 keventss
+ MOVW 8(R0), R2 // arg 3 nch
+ MOVW 12(R0), R3 // arg 4 ev
+ MOVW 16(R0), R4 // arg 5 nev
+ MOVW 20(R0), R5 // arg 6 ts
+ MOVW 0(R0), R0 // arg 1 kq
+ // Only R0-R3 are used for arguments, the rest
+ // go on the stack.
+ MOVM.DB.W [R4-R5], (R13)
+ BL libc_kevent(SB)
+ ADD $(2*4), R13
+ MOVW $-1, R2
+ CMP R0, R2
+ BNE ok
+ BL libc_error(SB)
+ MOVW (R0), R0 // errno
+ RSB $0, R0, R0 // caller wants it as a negative error code
+ok:
RET
-// int32 runtime·kqueue(void)
-TEXT runtime·kqueue(SB),NOSPLIT,$0
- MOVW $SYS_kqueue, R12
- SWI $0x80
- RSB.CS $0, R0, R0
- MOVW R0, ret+0(FP)
+TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 cmd
+ MOVW 8(R0), R2 // arg 3 arg
+ MOVW 0(R0), R0 // arg 1 fd
+ BL libc_fcntl(SB)
RET
-// int32 runtime·kevent(int kq, Kevent *changelist, int nchanges, Kevent *eventlist, int events, Timespec *timeout)
-TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVW $SYS_kevent, R12
- MOVW kq+0(FP), R0
- MOVW ch+4(FP), R1
- MOVW nch+8(FP), R2
- MOVW ev+12(FP), R3
- MOVW nev+16(FP), R4
- MOVW ts+20(FP), R5
- SWI $0x80
- RSB.CS $0, R0, R0
- MOVW R0, ret+24(FP)
- RET
-
-// int32 runtime·closeonexec(int32 fd)
-TEXT runtime·closeonexec(SB),NOSPLIT,$0
- MOVW $SYS_fcntl, R12
- MOVW fd+0(FP), R0
- MOVW $2, R1 // F_SETFD
- MOVW $1, R2 // FD_CLOEXEC
- SWI $0x80
- RET
-
-// sigaltstack on some darwin/arm version is buggy and will always
-// run the signal handler on the main stack, so our sigtramp has
+// sigaltstack is not supported on iOS, so our sigtramp has
// to do the stack switch ourselves.
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ MOVW $43, R0
+ BL libc_exit(SB)
RET
// Thread related functions
@@ -427,3 +339,43 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 sig
BL libc_raise(SB)
RET
+
+TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 attr
+ MOVW 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_init(SB)
+ RET
+
+TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
+ MOVW 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_lock(SB)
+ RET
+
+TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
+ MOVW 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_unlock(SB)
+ RET
+
+TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 attr
+ MOVW 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_init(SB)
+ RET
+
+TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 mutex
+ MOVW 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_wait(SB)
+ RET
+
+TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 mutex
+ MOVW 8(R0), R2 // arg 3 timeout
+ MOVW 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_timedwait_relative_np(SB)
+ RET
+
+TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
+ MOVW 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_signal(SB)
+ RET
diff --git a/src/runtime/sys_darwin_arm64.s b/src/runtime/sys_darwin_arm64.s
index d13e44afcf..c324994d26 100644
--- a/src/runtime/sys_darwin_arm64.s
+++ b/src/runtime/sys_darwin_arm64.s
@@ -3,26 +3,13 @@
// license that can be found in the LICENSE file.
// System calls and other sys.stuff for ARM64, Darwin
-// See http://fxr.watson.org/fxr/source/bsd/kern/syscalls.c?v=xnu-1228
-// or /usr/include/sys/syscall.h (on a Mac) for system call numbers.
+// System calls are implemented in libSystem, this file contains
+// trampolines that convert from Go to C calling convention.
#include "go_asm.h"
#include "go_tls.h"
#include "textflag.h"
-// Copied from /usr/include/sys/syscall.h
-#define SYS_gettimeofday 116
-#define SYS_kill 37
-#define SYS_getpid 20
-#define SYS_pthread_sigmask 329
-#define SYS_setitimer 83
-#define SYS___sysctl 202
-#define SYS_sigaction 46
-#define SYS_sigreturn 184
-#define SYS_kqueue 362
-#define SYS_kevent 363
-#define SYS_fcntl 92
-
TEXT notok<>(SB),NOSPLIT,$0
MOVD $0, R8
MOVD R8, (R8)
@@ -61,14 +48,12 @@ TEXT runtime·exit_trampoline(SB),NOSPLIT|NOFRAME,$0
MOVD $1002, R1
MOVD R0, (R1) // fail hard
-TEXT runtime·raiseproc(SB),NOSPLIT,$0
- MOVW $SYS_getpid, R16
- SVC $0x80
+TEXT runtime·raiseproc_trampoline(SB),NOSPLIT,$0
+ MOVD 0(R0), R19 // signal
+ BL libc_getpid(SB)
// arg 1 pid already in R0 from getpid
- MOVW sig+0(FP), R1 // arg 2 - signal
- MOVW $1, R2 // arg 3 - posix
- MOVW $SYS_kill, R16
- SVC $0x80
+ MOVD R19, R1 // arg 2 signal
+ BL libc_kill(SB)
RET
TEXT runtime·mmap_trampoline(SB),NOSPLIT,$0
@@ -108,12 +93,11 @@ TEXT runtime·madvise_trampoline(SB),NOSPLIT,$0
BL libc_madvise(SB)
RET
-TEXT runtime·setitimer(SB),NOSPLIT,$0
- MOVW mode+0(FP), R0
- MOVD new+8(FP), R1
- MOVD old+16(FP), R2
- MOVW $SYS_setitimer, R16
- SVC $0x80
+TEXT runtime·setitimer_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 new
+ MOVD 16(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 which
+ BL libc_setitimer(SB)
RET
TEXT runtime·walltime_trampoline(SB),NOSPLIT,$0
@@ -158,95 +142,104 @@ TEXT runtime·sigfwd(SB),NOSPLIT,$0-32
BL (R11)
RET
-// Sigtramp's job is to call the actual signal handler.
-// It is called with the following arguments on the stack:
-// LR "return address" - ignored
-// R0 actual handler
-// R1 siginfo style - ignored
-// R2 signal number
-// R3 siginfo
-// R4 context
TEXT runtime·sigtramp(SB),NOSPLIT,$0
+ // Reserve space for callee-save registers and arguments.
+ SUB $(8*16), RSP
+
+ // Save callee-save registers.
+ MOVD R19, (8*4)(RSP)
+ MOVD R20, (8*5)(RSP)
+ MOVD R21, (8*6)(RSP)
+ MOVD R22, (8*7)(RSP)
+ MOVD R23, (8*8)(RSP)
+ MOVD R24, (8*9)(RSP)
+ MOVD R25, (8*10)(RSP)
+ MOVD R26, (8*11)(RSP)
+ MOVD R27, (8*12)(RSP)
+ MOVD g, (8*13)(RSP)
+ MOVD R29, (8*14)(RSP)
+
+ // Save arguments.
+ MOVW R0, (8*1)(RSP) // sig
+ MOVD R1, (8*2)(RSP) // info
+ MOVD R2, (8*3)(RSP) // ctx
+
// this might be called in external code context,
// where g is not set.
- // first save R0, because runtime·load_g will clobber it
- MOVD.W R0, -16(RSP) // note: stack must be 16-byte aligned
MOVB runtime·iscgo(SB), R0
CMP $0, R0
BEQ 2(PC)
BL runtime·load_g(SB)
- CMP $0, g
- BNE cont
- // fake function call stack frame for badsignal
- // we only need to pass R2 (signal number), but
- // badsignal will expect R2 at 8(RSP), so we also
- // push R1 onto stack. turns out we do need R1
- // to do sigreturn.
- MOVD.W R1, -16(RSP)
- MOVD R2, 8(RSP)
- MOVD R4, 24(RSP) // save ucontext, badsignal might clobber R4
- MOVD $runtime·badsignal(SB), R26
- BL (R26)
- MOVD 0(RSP), R1 // saved infostype
- MOVD 24(RSP), R0 // the ucontext
- ADD $(16+16), RSP
- B ret
-
-cont:
- // Restore R0
- MOVD.P 16(RSP), R0
-
- // NOTE: some Darwin/ARM kernels always use the main stack to run the
- // signal handler. We need to switch to gsignal ourselves.
+ MOVD RSP, R6
+ CMP $0, g
+ BEQ nog
+ // iOS always use the main stack to run the signal handler.
+ // We need to switch to gsignal ourselves.
MOVD g_m(g), R11
MOVD m_gsignal(R11), R5
MOVD (g_stack+stack_hi)(R5), R6
- SUB $64, R6
-
- // copy arguments for call to sighandler
- MOVD R2, 8(R6) // signal num
- MOVD R3, 16(R6) // signal info
- MOVD R4, 24(R6) // context
- MOVD g, 32(R6) // old_g
-
- // Backup ucontext and infostyle
- MOVD R4, 40(R6)
- MOVD R1, 48(R6)
-
- // switch stack and g
- MOVD R6, RSP // sigtramp is not re-entrant, so no need to back up RSP.
- MOVD R5, g
-
- BL (R0)
-
- // call sigreturn
- MOVD 40(RSP), R0 // saved ucontext
- MOVD 48(RSP), R1 // saved infostyle
-ret:
- MOVW $SYS_sigreturn, R16 // sigreturn(ucontext, infostyle)
- SVC $0x80
-
- // if sigreturn fails, we can do nothing but exit
- B runtime·exit(SB)
-
-TEXT runtime·sigprocmask(SB),NOSPLIT,$0
- MOVW how+0(FP), R0
- MOVD new+8(FP), R1
- MOVD old+16(FP), R2
- MOVW $SYS_pthread_sigmask, R16
- SVC $0x80
- BCC 2(PC)
+
+nog:
+ // Restore arguments.
+ MOVW (8*1)(RSP), R0
+ MOVD (8*2)(RSP), R1
+ MOVD (8*3)(RSP), R2
+
+ // Reserve space for args and the stack pointer on the
+ // gsignal stack.
+ SUB $48, R6
+ // Save stack pointer.
+ MOVD RSP, R4
+ MOVD R4, (8*4)(R6)
+ // Switch to gsignal stack.
+ MOVD R6, RSP
+
+ // Call sigtrampgo.
+ MOVW R0, (8*1)(RSP)
+ MOVD R1, (8*2)(RSP)
+ MOVD R2, (8*3)(RSP)
+ MOVD $runtime·sigtrampgo(SB), R11
+ BL (R11)
+
+ // Switch to old stack.
+ MOVD (8*4)(RSP), R5
+ MOVD R5, RSP
+
+ // Restore callee-save registers.
+ MOVD (8*4)(RSP), R19
+ MOVD (8*5)(RSP), R20
+ MOVD (8*6)(RSP), R21
+ MOVD (8*7)(RSP), R22
+ MOVD (8*8)(RSP), R23
+ MOVD (8*9)(RSP), R24
+ MOVD (8*10)(RSP), R25
+ MOVD (8*11)(RSP), R26
+ MOVD (8*12)(RSP), R27
+ MOVD (8*13)(RSP), g
+ MOVD (8*14)(RSP), R29
+
+ ADD $(8*16), RSP
+
+ RET
+
+TEXT runtime·sigprocmask_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 new
+ MOVD 16(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 how
+ BL libc_pthread_sigmask(SB)
+ CMP $0, R0
+ BEQ 2(PC)
BL notok<>(SB)
RET
-TEXT runtime·sigaction(SB),NOSPLIT,$0
- MOVW mode+0(FP), R0
- MOVD new+8(FP), R1
- MOVD old+16(FP), R2
- MOVW $SYS_sigaction, R16
- SVC $0x80
- BCC 2(PC)
+TEXT runtime·sigaction_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 new
+ MOVD 16(R0), R2 // arg 3 old
+ MOVW 0(R0), R0 // arg 1 how
+ BL libc_sigaction(SB)
+ CMP $0, R0
+ BEQ 2(PC)
BL notok<>(SB)
RET
@@ -255,130 +248,50 @@ TEXT runtime·usleep_trampoline(SB),NOSPLIT,$0
BL libc_usleep(SB)
RET
-TEXT runtime·sysctl(SB),NOSPLIT,$0
- MOVD mib+0(FP), R0
- MOVW miblen+8(FP), R1
- MOVD out+16(FP), R2
- MOVD size+24(FP), R3
- MOVD dst+32(FP), R4
- MOVD ndst+40(FP), R5
- MOVW $SYS___sysctl, R16
- SVC $0x80
- BCC ok
- NEG R0, R0
- MOVW R0, ret+48(FP)
+TEXT runtime·sysctl_trampoline(SB),NOSPLIT,$0
+ MOVW 8(R0), R1 // arg 2 miblen
+ MOVD 16(R0), R2 // arg 3 out
+ MOVD 24(R0), R3 // arg 4 size
+ MOVD 32(R0), R4 // arg 5 dst
+ MOVD 40(R0), R5 // arg 6 ndst
+ MOVD 0(R0), R0 // arg 1 mib
+ BL libc_sysctl(SB)
+ RET
+
+TEXT runtime·kqueue_trampoline(SB),NOSPLIT,$0
+ BL libc_kqueue(SB)
RET
+
+TEXT runtime·kevent_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 keventt
+ MOVW 16(R0), R2 // arg 3 nch
+ MOVD 24(R0), R3 // arg 4 ev
+ MOVW 32(R0), R4 // arg 5 nev
+ MOVD 40(R0), R5 // arg 6 ts
+ MOVW 0(R0), R0 // arg 1 kq
+ BL libc_kevent(SB)
+ MOVD $-1, R2
+ CMP R0, R2
+ BNE ok
+ BL libc_error(SB)
+ MOVD (R0), R0 // errno
+ NEG R0, R0 // caller wants it as a negative error code
ok:
- MOVW $0, R0
- MOVW R0, ret+48(FP)
- RET
-
-// uint32 mach_msg_trap(void*, uint32, uint32, uint32, uint32, uint32, uint32)
-TEXT runtime·mach_msg_trap(SB),NOSPLIT,$0
- MOVD h+0(FP), R0
- MOVW op+8(FP), R1
- MOVW send_size+12(FP), R2
- MOVW rcv_size+16(FP), R3
- MOVW rcv_name+20(FP), R4
- MOVW timeout+24(FP), R5
- MOVW notify+28(FP), R6
- MOVN $30, R16
- SVC $0x80
- MOVW R0, ret+32(FP)
- RET
-
-TEXT runtime·mach_task_self(SB),NOSPLIT,$0
- MOVN $27, R16 // task_self_trap
- SVC $0x80
- MOVW R0, ret+0(FP)
- RET
-
-TEXT runtime·mach_thread_self(SB),NOSPLIT,$0
- MOVN $26, R16 // thread_self_trap
- SVC $0x80
- MOVW R0, ret+0(FP)
- RET
-
-TEXT runtime·mach_reply_port(SB),NOSPLIT,$0
- MOVN $25, R16 // mach_reply_port
- SVC $0x80
- MOVW R0, ret+0(FP)
- RET
-
-// Mach provides trap versions of the semaphore ops,
-// instead of requiring the use of RPC.
-
-// uint32 mach_semaphore_wait(uint32)
-TEXT runtime·mach_semaphore_wait(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MOVN $35, R16 // semaphore_wait_trap
- SVC $0x80
- MOVW R0, ret+8(FP)
- RET
-
-// uint32 mach_semaphore_timedwait(uint32, uint32, uint32)
-TEXT runtime·mach_semaphore_timedwait(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MOVW sec+4(FP), R1
- MOVW nsec+8(FP), R2
- MOVN $37, R16 // semaphore_timedwait_trap
- SVC $0x80
- MOVW R0, ret+16(FP)
- RET
-
-// uint32 mach_semaphore_signal(uint32)
-TEXT runtime·mach_semaphore_signal(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MOVN $32, R16 // semaphore_signal_trap
- SVC $0x80
- MOVW R0, ret+8(FP)
- RET
-
-// uint32 mach_semaphore_signal_all(uint32)
-TEXT runtime·mach_semaphore_signal_all(SB),NOSPLIT,$0
- MOVW sema+0(FP), R0
- MOVN $33, R16 // semaphore_signal_all_trap
- SVC $0x80
- MOVW R0, ret+8(FP)
- RET
-
-// int32 runtime·kqueue(void)
-TEXT runtime·kqueue(SB),NOSPLIT,$0
- MOVW $SYS_kqueue, R16
- SVC $0x80
- BCC 2(PC)
- NEG R0, R0
- MOVW R0, ret+0(FP)
- RET
-
-// int32 runtime·kevent(int kq, Kevent *ch, int nch, Kevent *ev, int nev, Timespec *ts)
-TEXT runtime·kevent(SB),NOSPLIT,$0
- MOVW kq+0(FP), R0
- MOVD ch+8(FP), R1
- MOVW nch+16(FP), R2
- MOVD ev+24(FP), R3
- MOVW nev+32(FP), R4
- MOVD ts+40(FP), R5
- MOVW $SYS_kevent, R16
- SVC $0x80
- BCC 2(PC)
- NEG R0, R0
- MOVW R0, ret+48(FP)
- RET
-
-// int32 runtime·closeonexec(int32 fd)
-TEXT runtime·closeonexec(SB),NOSPLIT,$0
- MOVW fd+0(FP), R0
- MOVW $2, R1 // F_SETFD
- MOVW $1, R2 // FD_CLOEXEC
- MOVW $SYS_fcntl, R16
- SVC $0x80
- RET
-
-// sigaltstack on some darwin/arm version is buggy and will always
+ RET
+
+TEXT runtime·fcntl_trampoline(SB),NOSPLIT,$0
+ MOVW 4(R0), R1 // arg 2 cmd
+ MOVW 8(R0), R2 // arg 3 arg
+ MOVW 0(R0), R0 // arg 1 fd
+ BL libc_fcntl(SB)
+ RET
+
+// sigaltstack on iOS is not supported and will always
// run the signal handler on the main stack, so our sigtramp has
// to do the stack switch ourselves.
-TEXT runtime·sigaltstack(SB),NOSPLIT,$0
+TEXT runtime·sigaltstack_trampoline(SB),NOSPLIT,$0
+ MOVW $43, R0
+ BL libc_exit(SB)
RET
// Thread related functions
@@ -415,3 +328,44 @@ TEXT runtime·raise_trampoline(SB),NOSPLIT,$0
MOVW 0(R0), R0 // arg 1 sig
BL libc_raise(SB)
RET
+
+TEXT runtime·pthread_mutex_init_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 attr
+ MOVD 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_init(SB)
+ RET
+
+TEXT runtime·pthread_mutex_lock_trampoline(SB),NOSPLIT,$0
+ MOVD 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_lock(SB)
+ RET
+
+TEXT runtime·pthread_mutex_unlock_trampoline(SB),NOSPLIT,$0
+ MOVD 0(R0), R0 // arg 1 mutex
+ BL libc_pthread_mutex_unlock(SB)
+ RET
+
+TEXT runtime·pthread_cond_init_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 attr
+ MOVD 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_init(SB)
+ RET
+
+TEXT runtime·pthread_cond_wait_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 mutex
+ MOVD 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_wait(SB)
+ RET
+
+TEXT runtime·pthread_cond_timedwait_relative_np_trampoline(SB),NOSPLIT,$0
+ MOVD 8(R0), R1 // arg 2 mutex
+ MOVD 16(R0), R2 // arg 3 timeout
+ MOVD 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_timedwait_relative_np(SB)
+ RET
+
+TEXT runtime·pthread_cond_signal_trampoline(SB),NOSPLIT,$0
+ MOVD 0(R0), R0 // arg 1 cond
+ BL libc_pthread_cond_signal(SB)
+ RET
+
diff --git a/src/runtime/sys_wasm.s b/src/runtime/sys_wasm.s
index 9a67ceec63..3ca844a4c7 100644
--- a/src/runtime/sys_wasm.s
+++ b/src/runtime/sys_wasm.s
@@ -149,13 +149,6 @@ TEXT runtime·wasmTruncU(SB), NOSPLIT, $0-0
I64TruncUF64
Return
-TEXT runtime·exit(SB), NOSPLIT, $0-8
- Call runtime·wasmExit(SB)
- Drop
- I32Const $0
- Set SP
- I32Const $1
-
TEXT runtime·exitThread(SB), NOSPLIT, $0-0
UNDEF
@@ -194,6 +187,14 @@ TEXT ·walltime(SB), NOSPLIT, $0
CallImport
RET
+TEXT ·scheduleCallback(SB), NOSPLIT, $0
+ CallImport
+ RET
+
+TEXT ·clearScheduledCallback(SB), NOSPLIT, $0
+ CallImport
+ RET
+
TEXT ·getRandomData(SB), NOSPLIT, $0
CallImport
RET
diff --git a/src/runtime/testdata/testprog/numcpu_freebsd.go b/src/runtime/testdata/testprog/numcpu_freebsd.go
index 035c53470b..42ee154883 100644
--- a/src/runtime/testdata/testprog/numcpu_freebsd.go
+++ b/src/runtime/testdata/testprog/numcpu_freebsd.go
@@ -9,12 +9,17 @@ import (
"fmt"
"os"
"os/exec"
+ "regexp"
"runtime"
"strconv"
"strings"
"syscall"
)
+var (
+ cpuSetRE = regexp.MustCompile(`(\d,?)+`)
+)
+
func init() {
register("FreeBSDNumCPU", FreeBSDNumCPU)
register("FreeBSDNumCPUHelper", FreeBSDNumCPUHelper)
@@ -105,8 +110,12 @@ func checkNCPU(list []string) error {
return fmt.Errorf("could not check against an empty CPU list")
}
+ cListString := cpuSetRE.FindString(listString)
+ if len(cListString) == 0 {
+ return fmt.Errorf("invalid cpuset output '%s'", listString)
+ }
// Launch FreeBSDNumCPUHelper() with specified CPUs list.
- cmd := exec.Command("cpuset", "-l", listString, os.Args[0], "FreeBSDNumCPUHelper")
+ cmd := exec.Command("cpuset", "-l", cListString, os.Args[0], "FreeBSDNumCPUHelper")
cmdline := strings.Join(cmd.Args, " ")
output, err := cmd.CombinedOutput()
if err != nil {
@@ -120,7 +129,7 @@ func checkNCPU(list []string) error {
return fmt.Errorf("fail to parse output from child '%s', error: %s, output: %s", cmdline, err, output)
}
if n != len(list) {
- return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, listString)
+ return fmt.Errorf("runtime.NumCPU() expected to %d, got %d when run with CPU list %s", len(list), n, cListString)
}
return nil
}
diff --git a/src/runtime/tls_ppc64x.s b/src/runtime/tls_ppc64x.s
index 69c0d9eb99..ed94989b69 100644
--- a/src/runtime/tls_ppc64x.s
+++ b/src/runtime/tls_ppc64x.s
@@ -46,4 +46,4 @@ TEXT runtime·load_g(SB),NOSPLIT|NOFRAME,$0-0
MOVD 0(R13)(R31*1), g
RET
-GLOBL runtime·tls_g+0(SB), TLSBSS, $8
+GLOBL runtime·tls_g+0(SB), TLSBSS+DUPOK, $8
diff --git a/src/runtime/trace/trace.go b/src/runtime/trace/trace.go
index b6a594355a..a40f87e53c 100644
--- a/src/runtime/trace/trace.go
+++ b/src/runtime/trace/trace.go
@@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package trace contains facilities for programs to generate trace
-// for Go execution tracer.
+// Package trace contains facilities for programs to generate traces
+// for the Go execution tracer.
//
// Tracing runtime activities
//
diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go
index 6d516b3afd..f790d3b17f 100644
--- a/src/runtime/vlrt.go
+++ b/src/runtime/vlrt.go
@@ -163,6 +163,7 @@ func int64div(n, d int64) int64 {
return q
}
+//go:nosplit
func int64mod(n, d int64) int64 {
// Check for 32 bit operands
if int64(int32(n)) == n && int64(int32(d)) == d {
diff --git a/src/strconv/atob.go b/src/strconv/atob.go
index 879ceb385e..0a495008d7 100644
--- a/src/strconv/atob.go
+++ b/src/strconv/atob.go
@@ -17,7 +17,7 @@ func ParseBool(str string) (bool, error) {
return false, syntaxError("ParseBool", str)
}
-// FormatBool returns "true" or "false" according to the value of b
+// FormatBool returns "true" or "false" according to the value of b.
func FormatBool(b bool) string {
if b {
return "true"
diff --git a/src/sync/rwmutex.go b/src/sync/rwmutex.go
index 9dbebfeed7..16a2f9227c 100644
--- a/src/sync/rwmutex.go
+++ b/src/sync/rwmutex.go
@@ -114,7 +114,6 @@ func (rw *RWMutex) Unlock() {
if race.Enabled {
_ = rw.w.state
race.Release(unsafe.Pointer(&rw.readerSem))
- race.Release(unsafe.Pointer(&rw.writerSem))
race.Disable()
}
diff --git a/src/syscall/asm_darwin_amd64.s b/src/syscall/asm_darwin_amd64.s
index 01f461b8b0..eab4fcdc06 100644
--- a/src/syscall/asm_darwin_amd64.s
+++ b/src/syscall/asm_darwin_amd64.s
@@ -117,7 +117,7 @@ ok1:
MOVQ $0, err+48(FP)
RET
-// func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
+// func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVQ a1+8(FP), DI
MOVQ a2+16(FP), SI
diff --git a/src/syscall/fs_js.go b/src/syscall/fs_js.go
index 141d46803c..36e9140759 100644
--- a/src/syscall/fs_js.go
+++ b/src/syscall/fs_js.go
@@ -15,8 +15,8 @@ import (
// Provided by package runtime.
func now() (sec int64, nsec int32)
-var jsProcess = js.Global.Get("process")
-var jsFS = js.Global.Get("fs")
+var jsProcess = js.Global().Get("process")
+var jsFS = js.Global().Get("fs")
var constants = jsFS.Get("constants")
var (
@@ -374,7 +374,9 @@ func Read(fd int, b []byte) (int, error) {
return n, err
}
- n, err := fsCall("readSync", fd, b, 0, len(b))
+ a := js.TypedArrayOf(b)
+ n, err := fsCall("readSync", fd, a, 0, len(b))
+ a.Release()
if err != nil {
return 0, err
}
@@ -395,7 +397,9 @@ func Write(fd int, b []byte) (int, error) {
return n, err
}
- n, err := fsCall("writeSync", fd, b, 0, len(b))
+ a := js.TypedArrayOf(b)
+ n, err := fsCall("writeSync", fd, a, 0, len(b))
+ a.Release()
if err != nil {
return 0, err
}
@@ -405,7 +409,9 @@ func Write(fd int, b []byte) (int, error) {
}
func Pread(fd int, b []byte, offset int64) (int, error) {
- n, err := fsCall("readSync", fd, b, 0, len(b), offset)
+ a := js.TypedArrayOf(b)
+ n, err := fsCall("readSync", fd, a, 0, len(b), offset)
+ a.Release()
if err != nil {
return 0, err
}
@@ -413,7 +419,9 @@ func Pread(fd int, b []byte, offset int64) (int, error) {
}
func Pwrite(fd int, b []byte, offset int64) (int, error) {
- n, err := fsCall("writeSync", fd, b, 0, len(b), offset)
+ a := js.TypedArrayOf(b)
+ n, err := fsCall("writeSync", fd, a, 0, len(b), offset)
+ a.Release()
if err != nil {
return 0, err
}
diff --git a/src/syscall/js/callback.go b/src/syscall/js/callback.go
new file mode 100644
index 0000000000..fa8a03ab0c
--- /dev/null
+++ b/src/syscall/js/callback.go
@@ -0,0 +1,147 @@
+// Copyright 2018 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 js,wasm
+
+package js
+
+import "sync"
+
+var pendingCallbacks = Global().Get("Array").New()
+
+var makeCallbackHelper = Global().Call("eval", `
+ (function(id, pendingCallbacks, resolveCallbackPromise) {
+ return function() {
+ pendingCallbacks.push({ id: id, args: arguments });
+ resolveCallbackPromise();
+ };
+ })
+`)
+
+var makeEventCallbackHelper = Global().Call("eval", `
+ (function(preventDefault, stopPropagation, stopImmediatePropagation, fn) {
+ return function(event) {
+ if (preventDefault) {
+ event.preventDefault();
+ }
+ if (stopPropagation) {
+ event.stopPropagation();
+ }
+ if (stopImmediatePropagation) {
+ event.stopImmediatePropagation();
+ }
+ fn(event);
+ };
+ })
+`)
+
+var (
+ callbacksMu sync.Mutex
+ callbacks = make(map[uint32]func([]Value))
+ nextCallbackID uint32 = 1
+)
+
+// Callback is a Go function that got wrapped for use as a JavaScript callback.
+// A Callback can be passed to functions of this package that accept interface{},
+// for example Value.Set and Value.Call.
+type Callback struct {
+ Value // the JavaScript function that queues the callback for execution
+ id uint32
+}
+
+// NewCallback returns a wrapped callback function. It can be passed to functions of this package
+// that accept interface{}, for example Value.Set and Value.Call.
+//
+// Invoking the callback in JavaScript will queue the Go function fn for execution.
+// This execution happens asynchronously on a special goroutine that handles all callbacks and preserves
+// the order in which the callbacks got called.
+// As a consequence, if one callback blocks this goroutine, other callbacks will not be processed.
+// A blocking callback should therefore explicitly start a new goroutine.
+//
+// Callback.Release must be called to free up resources when the callback will not be used any more.
+func NewCallback(fn func(args []Value)) Callback {
+ callbackLoopOnce.Do(func() {
+ go callbackLoop()
+ })
+
+ callbacksMu.Lock()
+ id := nextCallbackID
+ nextCallbackID++
+ callbacks[id] = fn
+ callbacksMu.Unlock()
+ return Callback{
+ Value: makeCallbackHelper.Invoke(id, pendingCallbacks, resolveCallbackPromise),
+ id: id,
+ }
+}
+
+type EventCallbackFlag int
+
+const (
+ // PreventDefault can be used with NewEventCallback to call event.preventDefault synchronously.
+ PreventDefault EventCallbackFlag = 1 << iota
+ // StopPropagation can be used with NewEventCallback to call event.stopPropagation synchronously.
+ StopPropagation
+ // StopImmediatePropagation can be used with NewEventCallback to call event.stopImmediatePropagation synchronously.
+ StopImmediatePropagation
+)
+
+// NewEventCallback returns a wrapped callback function, just like NewCallback, but the callback expects to have
+// exactly one argument, the event. Depending on flags, it will synchronously call event.preventDefault,
+// event.stopPropagation and/or event.stopImmediatePropagation before queuing the Go function fn for execution.
+func NewEventCallback(flags EventCallbackFlag, fn func(event Value)) Callback {
+ c := NewCallback(func(args []Value) {
+ fn(args[0])
+ })
+ return Callback{
+ Value: makeEventCallbackHelper.Invoke(
+ flags&PreventDefault != 0,
+ flags&StopPropagation != 0,
+ flags&StopImmediatePropagation != 0,
+ c,
+ ),
+ id: c.id,
+ }
+}
+
+// Release frees up resources allocated for the callback.
+// The callback must not be invoked after calling Release.
+func (c Callback) Release() {
+ callbacksMu.Lock()
+ delete(callbacks, c.id)
+ callbacksMu.Unlock()
+}
+
+var callbackLoopOnce sync.Once
+
+func callbackLoop() {
+ for {
+ sleepUntilCallback()
+ for {
+ cb := pendingCallbacks.Call("shift")
+ if cb == Undefined() {
+ break
+ }
+
+ id := uint32(cb.Get("id").Int())
+ callbacksMu.Lock()
+ f, ok := callbacks[id]
+ callbacksMu.Unlock()
+ if !ok {
+ Global().Get("console").Call("error", "call to closed callback")
+ continue
+ }
+
+ argsObj := cb.Get("args")
+ args := make([]Value, argsObj.Length())
+ for i := range args {
+ args[i] = argsObj.Index(i)
+ }
+ f(args)
+ }
+ }
+}
+
+// sleepUntilCallback is defined in the runtime package
+func sleepUntilCallback()
diff --git a/src/syscall/js/js.go b/src/syscall/js/js.go
index 9332a26254..7f0a5a1a8a 100644
--- a/src/syscall/js/js.go
+++ b/src/syscall/js/js.go
@@ -11,11 +11,37 @@
// comprehensive API for users. It is exempt from the Go compatibility promise.
package js
-import "unsafe"
+import (
+ "unsafe"
+)
+
+// ref is used to identify a JavaScript value, since the value itself can not be passed to WebAssembly.
+// A JavaScript number (64-bit float, except NaN) is represented by its IEEE 754 binary representation.
+// All other values are represented as an IEEE 754 binary representation of NaN with the low 32 bits
+// used as an ID.
+type ref uint64
+
+// nanHead are the upper 32 bits of a ref if the value is not a JavaScript number or NaN itself.
+const nanHead = 0x7FF80000
// Value represents a JavaScript value.
type Value struct {
- ref uint32
+ ref ref
+}
+
+func makeValue(v ref) Value {
+ return Value{ref: v}
+}
+
+func predefValue(id uint32) Value {
+ return Value{ref: nanHead<<32 | ref(id)}
+}
+
+func floatValue(f float64) Value {
+ if f != f {
+ return valueNaN
+ }
+ return Value{ref: *(*ref)(unsafe.Pointer(&f))}
}
// Error wraps a JavaScript error.
@@ -30,161 +56,218 @@ func (e Error) Error() string {
}
var (
- // Undefined is the JavaScript value "undefined". The zero Value equals to Undefined.
- Undefined = Value{0}
-
- // Null is the JavaScript value "null".
- Null = Value{1}
+ valueNaN = predefValue(0)
+ valueUndefined = predefValue(1)
+ valueNull = predefValue(2)
+ valueTrue = predefValue(3)
+ valueFalse = predefValue(4)
+ valueGlobal = predefValue(5)
+ memory = predefValue(6) // WebAssembly linear memory
+ resolveCallbackPromise = predefValue(7) // function that the callback helper uses to resume the execution of Go's WebAssembly code
+)
- // Global is the JavaScript global object, usually "window" or "global".
- Global = Value{2}
+// Undefined returns the JavaScript value "undefined".
+func Undefined() Value {
+ return valueUndefined
+}
- memory = Value{3}
-)
+// Null returns the JavaScript value "null".
+func Null() Value {
+ return valueNull
+}
-var uint8Array = Global.Get("Uint8Array")
+// Global returns the JavaScript global object, usually "window" or "global".
+func Global() Value {
+ return valueGlobal
+}
-// ValueOf returns x as a JavaScript value.
+// ValueOf returns x as a JavaScript value:
+//
+// | Go | JavaScript |
+// | --------------------- | --------------------- |
+// | js.Value | [its value] |
+// | js.TypedArray | [typed array] |
+// | js.Callback | function |
+// | nil | null |
+// | bool | boolean |
+// | integers and floats | number |
+// | string | string |
func ValueOf(x interface{}) Value {
switch x := x.(type) {
case Value:
return x
+ case TypedArray:
+ return x.Value
+ case Callback:
+ return x.Value
case nil:
- return Null
+ return valueNull
case bool:
- return boolVal(x)
+ if x {
+ return valueTrue
+ } else {
+ return valueFalse
+ }
case int:
- return intVal(x)
+ return floatValue(float64(x))
case int8:
- return intVal(int(x))
+ return floatValue(float64(x))
case int16:
- return intVal(int(x))
+ return floatValue(float64(x))
case int32:
- return intVal(int(x))
+ return floatValue(float64(x))
case int64:
- return intVal(int(x))
+ return floatValue(float64(x))
case uint:
- return intVal(int(x))
+ return floatValue(float64(x))
case uint8:
- return intVal(int(x))
+ return floatValue(float64(x))
case uint16:
- return intVal(int(x))
+ return floatValue(float64(x))
case uint32:
- return intVal(int(x))
+ return floatValue(float64(x))
case uint64:
- return intVal(int(x))
+ return floatValue(float64(x))
case uintptr:
- return intVal(int(x))
+ return floatValue(float64(x))
case unsafe.Pointer:
- return intVal(int(uintptr(x)))
+ return floatValue(float64(uintptr(x)))
case float32:
- return floatVal(float64(x))
+ return floatValue(float64(x))
case float64:
- return floatVal(x)
+ return floatValue(x)
case string:
- return stringVal(x)
- case []byte:
- if len(x) == 0 {
- return uint8Array.New(memory.Get("buffer"), 0, 0)
- }
- return uint8Array.New(memory.Get("buffer"), unsafe.Pointer(&x[0]), len(x))
+ return makeValue(stringVal(x))
default:
- panic("invalid value")
+ panic("ValueOf: invalid value")
}
}
-func boolVal(x bool) Value
-
-func intVal(x int) Value
-
-func floatVal(x float64) Value
-
-func stringVal(x string) Value
+func stringVal(x string) ref
// Get returns the JavaScript property p of value v.
-func (v Value) Get(p string) Value
+func (v Value) Get(p string) Value {
+ return makeValue(valueGet(v.ref, p))
+}
+
+func valueGet(v ref, p string) ref
// Set sets the JavaScript property p of value v to x.
func (v Value) Set(p string, x interface{}) {
- v.set(p, ValueOf(x))
+ valueSet(v.ref, p, ValueOf(x).ref)
}
-func (v Value) set(p string, x Value)
+func valueSet(v ref, p string, x ref)
// Index returns JavaScript index i of value v.
-func (v Value) Index(i int) Value
+func (v Value) Index(i int) Value {
+ return makeValue(valueIndex(v.ref, i))
+}
+
+func valueIndex(v ref, i int) ref
// SetIndex sets the JavaScript index i of value v to x.
func (v Value) SetIndex(i int, x interface{}) {
- v.setIndex(i, ValueOf(x))
+ valueSetIndex(v.ref, i, ValueOf(x).ref)
}
-func (v Value) setIndex(i int, x Value)
+func valueSetIndex(v ref, i int, x ref)
-func makeArgs(args []interface{}) []Value {
- argVals := make([]Value, len(args))
+func makeArgs(args []interface{}) []ref {
+ argVals := make([]ref, len(args))
for i, arg := range args {
- argVals[i] = ValueOf(arg)
+ argVals[i] = ValueOf(arg).ref
}
return argVals
}
// Length returns the JavaScript property "length" of v.
-func (v Value) Length() int
+func (v Value) Length() int {
+ return valueLength(v.ref)
+}
+
+func valueLength(v ref) int
// Call does a JavaScript call to the method m of value v with the given arguments.
// It panics if v has no method m.
func (v Value) Call(m string, args ...interface{}) Value {
- res, ok := v.call(m, makeArgs(args))
+ res, ok := valueCall(v.ref, m, makeArgs(args))
if !ok {
- panic(Error{res})
+ panic(Error{makeValue(res)})
}
- return res
+ return makeValue(res)
}
-func (v Value) call(m string, args []Value) (Value, bool)
+func valueCall(v ref, m string, args []ref) (ref, bool)
// Invoke does a JavaScript call of the value v with the given arguments.
// It panics if v is not a function.
func (v Value) Invoke(args ...interface{}) Value {
- res, ok := v.invoke(makeArgs(args))
+ res, ok := valueInvoke(v.ref, makeArgs(args))
if !ok {
- panic(Error{res})
+ panic(Error{makeValue(res)})
}
- return res
+ return makeValue(res)
}
-func (v Value) invoke(args []Value) (Value, bool)
+func valueInvoke(v ref, args []ref) (ref, bool)
// New uses JavaScript's "new" operator with value v as constructor and the given arguments.
// It panics if v is not a function.
func (v Value) New(args ...interface{}) Value {
- res, ok := v.new(makeArgs(args))
+ res, ok := valueNew(v.ref, makeArgs(args))
if !ok {
- panic(Error{res})
+ panic(Error{makeValue(res)})
}
- return res
+ return makeValue(res)
}
-func (v Value) new(args []Value) (Value, bool)
+func valueNew(v ref, args []ref) (ref, bool)
-// Float returns the value v converted to float64 according to JavaScript type conversions (parseFloat).
-func (v Value) Float() float64
+func (v Value) isNumber() bool {
+ return v.ref>>32 != nanHead || v.ref == valueNaN.ref
+}
-// Int returns the value v converted to int according to JavaScript type conversions (parseInt).
-func (v Value) Int() int
+// Float returns the value v as a float64. It panics if v is not a JavaScript number.
+func (v Value) Float() float64 {
+ if !v.isNumber() {
+ panic("syscall/js: not a number")
+ }
+ return *(*float64)(unsafe.Pointer(&v.ref))
+}
-// Bool returns the value v converted to bool according to JavaScript type conversions.
-func (v Value) Bool() bool
+// Int returns the value v truncated to an int. It panics if v is not a JavaScript number.
+func (v Value) Int() int {
+ return int(v.Float())
+}
+
+// Bool returns the value v as a bool. It panics if v is not a JavaScript boolean.
+func (v Value) Bool() bool {
+ switch v.ref {
+ case valueTrue.ref:
+ return true
+ case valueFalse.ref:
+ return false
+ default:
+ panic("syscall/js: not a boolean")
+ }
+}
// String returns the value v converted to string according to JavaScript type conversions.
func (v Value) String() string {
- str, length := v.prepareString()
+ str, length := valuePrepareString(v.ref)
b := make([]byte, length)
- str.loadString(b)
+ valueLoadString(str, b)
return string(b)
}
-func (v Value) prepareString() (Value, int)
+func valuePrepareString(v ref) (ref, int)
+
+func valueLoadString(v ref, b []byte)
+
+// InstanceOf reports whether v is an instance of type t according to JavaScript's instanceof operator.
+func (v Value) InstanceOf(t Value) bool {
+ return valueInstanceOf(v.ref, t.ref)
+}
-func (v Value) loadString(b []byte)
+func valueInstanceOf(v ref, t ref) bool
diff --git a/src/syscall/js/js_js.s b/src/syscall/js/js_js.s
index f5bc02ec67..0ec164d5cb 100644
--- a/src/syscall/js/js_js.s
+++ b/src/syscall/js/js_js.s
@@ -4,70 +4,50 @@
#include "textflag.h"
-TEXT ·boolVal(SB), NOSPLIT, $0
- CallImport
- RET
-
-TEXT ·intVal(SB), NOSPLIT, $0
- CallImport
- RET
-
-TEXT ·floatVal(SB), NOSPLIT, $0
- CallImport
- RET
-
TEXT ·stringVal(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·Get(SB), NOSPLIT, $0
- CallImport
- RET
-
-TEXT ·Value·set(SB), NOSPLIT, $0
- CallImport
- RET
-
-TEXT ·Value·Index(SB), NOSPLIT, $0
+TEXT ·valueGet(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·setIndex(SB), NOSPLIT, $0
+TEXT ·valueSet(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·call(SB), NOSPLIT, $0
+TEXT ·valueIndex(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·invoke(SB), NOSPLIT, $0
+TEXT ·valueSetIndex(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·new(SB), NOSPLIT, $0
+TEXT ·valueCall(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·Float(SB), NOSPLIT, $0
+TEXT ·valueInvoke(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·Int(SB), NOSPLIT, $0
+TEXT ·valueNew(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·Bool(SB), NOSPLIT, $0
+TEXT ·valueLength(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·Length(SB), NOSPLIT, $0
+TEXT ·valuePrepareString(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·prepareString(SB), NOSPLIT, $0
+TEXT ·valueLoadString(SB), NOSPLIT, $0
CallImport
RET
-TEXT ·Value·loadString(SB), NOSPLIT, $0
+TEXT ·valueInstanceOf(SB), NOSPLIT, $0
CallImport
RET
diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go
index ca065e321d..497b9467bb 100644
--- a/src/syscall/js/js_test.go
+++ b/src/syscall/js/js_test.go
@@ -7,11 +7,13 @@
package js_test
import (
+ "fmt"
+ "math"
"syscall/js"
"testing"
)
-var dummys = js.Global.Call("eval", `({
+var dummys = js.Global().Call("eval", `({
someBool: true,
someString: "abc\u1234",
someInt: 42,
@@ -20,6 +22,7 @@ var dummys = js.Global.Call("eval", `({
add: function(a, b) {
return a + b;
},
+ NaN: NaN,
})`)
func TestBool(t *testing.T) {
@@ -32,6 +35,9 @@ func TestBool(t *testing.T) {
if got := dummys.Get("otherBool").Bool(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
+ if dummys.Get("someBool") != dummys.Get("someBool") {
+ t.Errorf("same value not equal")
+ }
}
func TestString(t *testing.T) {
@@ -44,6 +50,9 @@ func TestString(t *testing.T) {
if got := dummys.Get("otherString").String(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
+ if dummys.Get("someString") != dummys.Get("someString") {
+ t.Errorf("same value not equal")
+ }
}
func TestInt(t *testing.T) {
@@ -56,6 +65,9 @@ func TestInt(t *testing.T) {
if got := dummys.Get("otherInt").Int(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
+ if dummys.Get("someInt") != dummys.Get("someInt") {
+ t.Errorf("same value not equal")
+ }
}
func TestIntConversion(t *testing.T) {
@@ -86,19 +98,58 @@ func TestFloat(t *testing.T) {
if got := dummys.Get("otherFloat").Float(); got != want {
t.Errorf("got %#v, want %#v", got, want)
}
+ if dummys.Get("someFloat") != dummys.Get("someFloat") {
+ t.Errorf("same value not equal")
+ }
+}
+
+func TestObject(t *testing.T) {
+ if dummys.Get("someArray") != dummys.Get("someArray") {
+ t.Errorf("same value not equal")
+ }
+}
+
+func TestTypedArrayOf(t *testing.T) {
+ testTypedArrayOf(t, "[]int8", []int8{0, -42, 0}, -42)
+ testTypedArrayOf(t, "[]int16", []int16{0, -42, 0}, -42)
+ testTypedArrayOf(t, "[]int32", []int32{0, -42, 0}, -42)
+ testTypedArrayOf(t, "[]uint8", []uint8{0, 42, 0}, 42)
+ testTypedArrayOf(t, "[]uint16", []uint16{0, 42, 0}, 42)
+ testTypedArrayOf(t, "[]uint32", []uint32{0, 42, 0}, 42)
+ testTypedArrayOf(t, "[]float32", []float32{0, -42.5, 0}, -42.5)
+ testTypedArrayOf(t, "[]float64", []float64{0, -42.5, 0}, -42.5)
+}
+
+func testTypedArrayOf(t *testing.T, name string, slice interface{}, want float64) {
+ t.Run(name, func(t *testing.T) {
+ a := js.TypedArrayOf(slice)
+ got := a.Index(1).Float()
+ a.Release()
+ if got != want {
+ t.Errorf("got %#v, want %#v", got, want)
+ }
+ })
+}
+
+func TestNaN(t *testing.T) {
+ want := js.ValueOf(math.NaN())
+ got := dummys.Get("NaN")
+ if got != want {
+ t.Errorf("got %#v, want %#v", got, want)
+ }
}
func TestUndefined(t *testing.T) {
- dummys.Set("test", js.Undefined)
- if dummys == js.Undefined || dummys.Get("test") != js.Undefined || dummys.Get("xyz") != js.Undefined {
+ dummys.Set("test", js.Undefined())
+ if dummys == js.Undefined() || dummys.Get("test") != js.Undefined() || dummys.Get("xyz") != js.Undefined() {
t.Errorf("js.Undefined expected")
}
}
func TestNull(t *testing.T) {
dummys.Set("test1", nil)
- dummys.Set("test2", js.Null)
- if dummys == js.Null || dummys.Get("test1") != js.Null || dummys.Get("test2") != js.Null {
+ dummys.Set("test2", js.Null())
+ if dummys == js.Null() || dummys.Get("test1") != js.Null() || dummys.Get("test2") != js.Null() {
t.Errorf("js.Null expected")
}
}
@@ -127,7 +178,7 @@ func TestCall(t *testing.T) {
if got := dummys.Call("add", i, 2).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
- if got := dummys.Call("add", js.Global.Call("eval", "40"), 2).Int(); got != 42 {
+ if got := dummys.Call("add", js.Global().Call("eval", "40"), 2).Int(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
@@ -140,7 +191,66 @@ func TestInvoke(t *testing.T) {
}
func TestNew(t *testing.T) {
- if got := js.Global.Get("Array").New(42).Length(); got != 42 {
+ if got := js.Global().Get("Array").New(42).Length(); got != 42 {
t.Errorf("got %#v, want %#v", got, 42)
}
}
+
+func TestInstanceOf(t *testing.T) {
+ someArray := js.Global().Get("Array").New()
+ if got, want := someArray.InstanceOf(js.Global().Get("Array")), true; got != want {
+ t.Errorf("got %#v, want %#v", got, want)
+ }
+ if got, want := someArray.InstanceOf(js.Global().Get("Function")), false; got != want {
+ t.Errorf("got %#v, want %#v", got, want)
+ }
+}
+
+func TestCallback(t *testing.T) {
+ c := make(chan struct{})
+ cb := js.NewCallback(func(args []js.Value) {
+ if got := args[0].Int(); got != 42 {
+ t.Errorf("got %#v, want %#v", got, 42)
+ }
+ c <- struct{}{}
+ })
+ defer cb.Release()
+ js.Global().Call("setTimeout", cb, 0, 42)
+ <-c
+}
+
+func TestEventCallback(t *testing.T) {
+ for _, name := range []string{"preventDefault", "stopPropagation", "stopImmediatePropagation"} {
+ c := make(chan struct{})
+ var flags js.EventCallbackFlag
+ switch name {
+ case "preventDefault":
+ flags = js.PreventDefault
+ case "stopPropagation":
+ flags = js.StopPropagation
+ case "stopImmediatePropagation":
+ flags = js.StopImmediatePropagation
+ }
+ cb := js.NewEventCallback(flags, func(event js.Value) {
+ c <- struct{}{}
+ })
+ defer cb.Release()
+
+ event := js.Global().Call("eval", fmt.Sprintf("({ called: false, %s: function() { this.called = true; } })", name))
+ cb.Invoke(event)
+ if !event.Get("called").Bool() {
+ t.Errorf("%s not called", name)
+ }
+
+ <-c
+ }
+}
+
+func ExampleNewCallback() {
+ var cb js.Callback
+ cb = js.NewCallback(func(args []js.Value) {
+ fmt.Println("button clicked")
+ cb.Release() // release the callback if the button will not be clicked again
+ })
+ js.Global().Get("document").Call("getElementById", "myButton").Call("addEventListener", "click", cb)
+}
diff --git a/src/syscall/js/typedarray.go b/src/syscall/js/typedarray.go
new file mode 100644
index 0000000000..e824197258
--- /dev/null
+++ b/src/syscall/js/typedarray.go
@@ -0,0 +1,103 @@
+// Copyright 2018 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 js,wasm
+
+package js
+
+import (
+ "sync"
+ "unsafe"
+)
+
+var (
+ int8Array = Global().Get("Int8Array")
+ int16Array = Global().Get("Int16Array")
+ int32Array = Global().Get("Int32Array")
+ uint8Array = Global().Get("Uint8Array")
+ uint16Array = Global().Get("Uint16Array")
+ uint32Array = Global().Get("Uint32Array")
+ float32Array = Global().Get("Float32Array")
+ float64Array = Global().Get("Float64Array")
+)
+
+// TypedArray represents a JavaScript typed array.
+type TypedArray struct {
+ Value
+}
+
+// Release frees up resources allocated for the typed array.
+// The typed array and its buffer must not be accessed after calling Release.
+func (a TypedArray) Release() {
+ openTypedArraysMutex.Lock()
+ delete(openTypedArrays, a)
+ openTypedArraysMutex.Unlock()
+}
+
+var (
+ openTypedArraysMutex sync.Mutex
+ openTypedArrays = make(map[TypedArray]interface{})
+)
+
+// TypedArrayOf returns a JavaScript typed array backed by the slice's underlying array.
+// It can be passed to functions of this package that accept interface{}, for example Value.Set and Value.Call.
+//
+// The supported types are []int8, []int16, []int32, []uint8, []uint16, []uint32, []float32 and []float64.
+// Passing an unsupported value causes a panic.
+//
+// TypedArray.Release must be called to free up resources when the typed array will not be used any more.
+func TypedArrayOf(slice interface{}) TypedArray {
+ a := TypedArray{typedArrayOf(slice)}
+ openTypedArraysMutex.Lock()
+ openTypedArrays[a] = slice
+ openTypedArraysMutex.Unlock()
+ return a
+}
+
+func typedArrayOf(slice interface{}) Value {
+ switch slice := slice.(type) {
+ case []int8:
+ if len(slice) == 0 {
+ return int8Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return int8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []int16:
+ if len(slice) == 0 {
+ return int16Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return int16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []int32:
+ if len(slice) == 0 {
+ return int32Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return int32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []uint8:
+ if len(slice) == 0 {
+ return uint8Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return uint8Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []uint16:
+ if len(slice) == 0 {
+ return uint16Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return uint16Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []uint32:
+ if len(slice) == 0 {
+ return uint32Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return uint32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []float32:
+ if len(slice) == 0 {
+ return float32Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return float32Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ case []float64:
+ if len(slice) == 0 {
+ return float64Array.New(memory.Get("buffer"), 0, 0)
+ }
+ return float64Array.New(memory.Get("buffer"), unsafe.Pointer(&slice[0]), len(slice))
+ default:
+ panic("TypedArrayOf: not a supported slice")
+ }
+}
diff --git a/src/syscall/mkall.sh b/src/syscall/mkall.sh
index cd0783e876..b381b93161 100755
--- a/src/syscall/mkall.sh
+++ b/src/syscall/mkall.sh
@@ -189,6 +189,36 @@ linux_arm64)
# API consistent between platforms.
mktypes="GOARCH=$GOARCH go tool cgo -godefs -- -fsigned-char"
;;
+linux_mips)
+ GOOSARCH_in=syscall_linux_mipsx.go
+ unistd_h=/usr/include/asm/unistd.h
+ mksyscall="./mksyscall.pl -b32 -arm"
+ mkerrors="$mkerrors"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+linux_mipsle)
+ GOOSARCH_in=syscall_linux_mipsx.go
+ unistd_h=/usr/include/asm/unistd.h
+ mksyscall="./mksyscall.pl -l32 -arm"
+ mkerrors="$mkerrors"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+linux_mips64)
+ GOOSARCH_in=syscall_linux_mips64x.go
+ unistd_h=/usr/include/asm/unistd.h
+ mkerrors="$mkerrors -m64"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
+linux_mips64le)
+ GOOSARCH_in=syscall_linux_mips64x.go
+ unistd_h=/usr/include/asm/unistd.h
+ mkerrors="$mkerrors -m64"
+ mksysnum="./mksysnum_linux.pl $unistd_h"
+ mktypes="GOARCH=$GOARCH go tool cgo -godefs"
+ ;;
linux_ppc64)
GOOSARCH_in=syscall_linux_ppc64x.go
unistd_h=/usr/include/asm/unistd.h
diff --git a/src/syscall/mkerrors.sh b/src/syscall/mkerrors.sh
index b59a46b18f..93d6f7d2b6 100755
--- a/src/syscall/mkerrors.sh
+++ b/src/syscall/mkerrors.sh
@@ -344,7 +344,7 @@ echo '#include <signal.h>' | $CC -x c - -E -dM $ccflags |
sort >_signal.grep
echo '// mkerrors.sh' "$@"
-echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
+echo '// Code generated by the command above; DO NOT EDIT.'
echo
go tool cgo -godefs -- "$@" _const.go >_error.out
cat _error.out | grep -vf _error.grep | grep -vf _signal.grep
diff --git a/src/syscall/mksyscall.pl b/src/syscall/mksyscall.pl
index 894f828d59..ccce82e172 100755
--- a/src/syscall/mksyscall.pl
+++ b/src/syscall/mksyscall.pl
@@ -317,7 +317,7 @@ if($errors) {
print <<EOF;
// $cmdline
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build $tags
diff --git a/src/syscall/mksyscall_solaris.pl b/src/syscall/mksyscall_solaris.pl
index a4cc1ace57..9172975914 100755
--- a/src/syscall/mksyscall_solaris.pl
+++ b/src/syscall/mksyscall_solaris.pl
@@ -261,7 +261,7 @@ if($errors) {
print <<EOF;
// $cmdline
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build $tags
diff --git a/src/syscall/mksyscall_windows.go b/src/syscall/mksyscall_windows.go
index e7c8664ee0..5fd3a756f8 100644
--- a/src/syscall/mksyscall_windows.go
+++ b/src/syscall/mksyscall_windows.go
@@ -815,7 +815,7 @@ func main() {
// TODO: use println instead to print in the following template
const srcTemplate = `
-{{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+{{define "main"}}// Code generated by 'go generate'; DO NOT EDIT.
package {{packagename}}
diff --git a/src/syscall/mksysctl_openbsd.pl b/src/syscall/mksysctl_openbsd.pl
index c2e2ea925d..ea462a7fda 100755
--- a/src/syscall/mksysctl_openbsd.pl
+++ b/src/syscall/mksysctl_openbsd.pl
@@ -235,7 +235,7 @@ foreach my $header (@headers) {
print <<EOF;
// mksysctl_openbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall;
diff --git a/src/syscall/mksysnum_darwin.pl b/src/syscall/mksysnum_darwin.pl
index e3470435d2..af21e855ae 100755
--- a/src/syscall/mksysnum_darwin.pl
+++ b/src/syscall/mksysnum_darwin.pl
@@ -11,7 +11,7 @@ my $command = "mksysnum_darwin.pl " . join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_dragonfly.pl b/src/syscall/mksysnum_dragonfly.pl
index 3eba3ab3d5..e9a634b513 100755
--- a/src/syscall/mksysnum_dragonfly.pl
+++ b/src/syscall/mksysnum_dragonfly.pl
@@ -12,7 +12,7 @@ my $command = "mksysnum_dragonfly.pl " . join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_freebsd.pl b/src/syscall/mksysnum_freebsd.pl
index cd675780b5..c04ada9e2f 100755
--- a/src/syscall/mksysnum_freebsd.pl
+++ b/src/syscall/mksysnum_freebsd.pl
@@ -12,7 +12,7 @@ my $command = "mksysnum_freebsd.pl " . join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_linux.pl b/src/syscall/mksysnum_linux.pl
index 4db8149c4c..5fb1d0ee8b 100755
--- a/src/syscall/mksysnum_linux.pl
+++ b/src/syscall/mksysnum_linux.pl
@@ -9,7 +9,7 @@ my $command = "mksysnum_linux.pl ". join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_netbsd.pl b/src/syscall/mksysnum_netbsd.pl
index f1534ed584..4f5150a04d 100755
--- a/src/syscall/mksysnum_netbsd.pl
+++ b/src/syscall/mksysnum_netbsd.pl
@@ -12,7 +12,7 @@ my $command = "mksysnum_netbsd.pl " . join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_openbsd.pl b/src/syscall/mksysnum_openbsd.pl
index ad1ccc12ac..0b0c9df199 100755
--- a/src/syscall/mksysnum_openbsd.pl
+++ b/src/syscall/mksysnum_openbsd.pl
@@ -12,7 +12,7 @@ my $command = "mksysnum_openbsd.pl " . join(' ', @ARGV);
print <<EOF;
// $command
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/mksysnum_plan9.sh b/src/syscall/mksysnum_plan9.sh
index cd29dd55cf..5ac35a9f0a 100755
--- a/src/syscall/mksysnum_plan9.sh
+++ b/src/syscall/mksysnum_plan9.sh
@@ -7,7 +7,7 @@ COMMAND="mksysnum_plan9.sh $@"
cat <<EOF
// $COMMAND
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/net_js.go b/src/syscall/net_js.go
index 0149e2bfc5..d5bf1f4f99 100644
--- a/src/syscall/net_js.go
+++ b/src/syscall/net_js.go
@@ -38,6 +38,13 @@ const (
SO_ERROR
)
+// Misc constants expected by package net but not supported.
+const (
+ _ = iota
+ F_DUPFD_CLOEXEC
+ SYS_FCNTL = 500 // unsupported; same value as net_nacl.go
+)
+
type Sockaddr interface {
}
diff --git a/src/syscall/security_windows.go b/src/syscall/security_windows.go
index dbaf6d3264..ae8b3a17bf 100644
--- a/src/syscall/security_windows.go
+++ b/src/syscall/security_windows.go
@@ -221,6 +221,7 @@ const (
TOKEN_ADJUST_PRIVILEGES
TOKEN_ADJUST_GROUPS
TOKEN_ADJUST_DEFAULT
+ TOKEN_ADJUST_SESSIONID
TOKEN_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED |
TOKEN_ASSIGN_PRIMARY |
@@ -230,7 +231,8 @@ const (
TOKEN_QUERY_SOURCE |
TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_GROUPS |
- TOKEN_ADJUST_DEFAULT
+ TOKEN_ADJUST_DEFAULT |
+ TOKEN_ADJUST_SESSIONID
TOKEN_READ = STANDARD_RIGHTS_READ | TOKEN_QUERY
TOKEN_WRITE = STANDARD_RIGHTS_WRITE |
TOKEN_ADJUST_PRIVILEGES |
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 58216f1957..1a304c4966 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -35,6 +35,31 @@ func Creat(path string, mode uint32) (fd int, err error) {
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
}
+//sys faccessat(dirfd int, path string, mode uint32) (err error)
+
+func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
+ if flags & ^(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 {
+ return EINVAL
+ } else if flags&(_AT_SYMLINK_NOFOLLOW|_AT_EACCESS) != 0 {
+ return EOPNOTSUPP
+ }
+ return faccessat(dirfd, path, mode)
+}
+
+//sys fchmodat(dirfd int, path string, mode uint32) (err error)
+
+func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
+ // Linux fchmodat doesn't support the flags parameter. Mimick glibc's behavior
+ // and check the flags. Otherwise the mode would be applied to the symlink
+ // destination which is not what the user expects.
+ if flags&^_AT_SYMLINK_NOFOLLOW != 0 {
+ return EINVAL
+ } else if flags&_AT_SYMLINK_NOFOLLOW != 0 {
+ return EOPNOTSUPP
+ }
+ return fchmodat(dirfd, path, mode)
+}
+
//sys linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
func Link(oldpath string, newpath string) (err error) {
@@ -826,11 +851,9 @@ func Mount(source string, target string, fstype string, flags uintptr, data stri
//sysnb EpollCreate(size int) (fd int, err error)
//sysnb EpollCreate1(flag int) (fd int, err error)
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
-//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
//sys Fchdir(fd int) (err error)
//sys Fchmod(fd int, mode uint32) (err error)
-//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
//sys Fdatasync(fd int) (err error)
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
index 932ccee491..24158bb8b8 100644
--- a/src/syscall/syscall_linux_test.go
+++ b/src/syscall/syscall_linux_test.go
@@ -21,6 +21,100 @@ import (
"time"
)
+// chtmpdir changes the working directory to a new temporary directory and
+// provides a cleanup function. Used when PWD is read-only.
+func chtmpdir(t *testing.T) func() {
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ d, err := ioutil.TempDir("", "test")
+ if err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ if err := os.Chdir(d); err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ return func() {
+ if err := os.Chdir(oldwd); err != nil {
+ t.Fatalf("chtmpdir: %v", err)
+ }
+ os.RemoveAll(d)
+ }
+}
+
+func touch(t *testing.T, name string) {
+ f, err := os.Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Fatal(err)
+ }
+}
+
+const (
+ _AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_FDCWD = -0x64
+ _AT_EACCESS = 0x200
+)
+
+func TestFaccessat(t *testing.T) {
+ defer chtmpdir(t)()
+ touch(t, "file1")
+
+ err := syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, 0)
+ if err != nil {
+ t.Errorf("Faccessat: unexpected error: %v", err)
+ }
+
+ err = syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, 2)
+ if err != syscall.EINVAL {
+ t.Errorf("Faccessat: unexpected error: %v, want EINVAL", err)
+ }
+
+ err = syscall.Faccessat(_AT_FDCWD, "file1", syscall.O_RDONLY, _AT_EACCESS)
+ if err != syscall.EOPNOTSUPP {
+ t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err)
+ }
+
+ err = os.Symlink("file1", "symlink1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ err = syscall.Faccessat(_AT_FDCWD, "symlink1", syscall.O_RDONLY, _AT_SYMLINK_NOFOLLOW)
+ if err != syscall.EOPNOTSUPP {
+ t.Errorf("Faccessat: unexpected error: %v, want EOPNOTSUPP", err)
+ }
+}
+
+func TestFchmodat(t *testing.T) {
+ defer chtmpdir(t)()
+
+ touch(t, "file1")
+ os.Symlink("file1", "symlink1")
+
+ err := syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, 0)
+ if err != nil {
+ t.Fatalf("Fchmodat: unexpected error: %v", err)
+ }
+
+ fi, err := os.Stat("file1")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if fi.Mode() != 0444 {
+ t.Errorf("Fchmodat: failed to change mode: expected %v, got %v", 0444, fi.Mode())
+ }
+
+ err = syscall.Fchmodat(_AT_FDCWD, "symlink1", 0444, _AT_SYMLINK_NOFOLLOW)
+ if err != syscall.EOPNOTSUPP {
+ t.Fatalf("Fchmodat: unexpected error: %v, expected EOPNOTSUPP", err)
+ }
+}
+
func TestMain(m *testing.M) {
if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
deathSignalParent()
diff --git a/src/syscall/syscall_windows_test.go b/src/syscall/syscall_windows_test.go
index 86842f2ad2..d146911073 100644
--- a/src/syscall/syscall_windows_test.go
+++ b/src/syscall/syscall_windows_test.go
@@ -70,3 +70,9 @@ func ExampleLoadLibrary() {
build := uint16(r >> 16)
print("windows version ", major, ".", minor, " (Build ", build, ")\n")
}
+
+func TestTOKEN_ALL_ACCESS(t *testing.T) {
+ if syscall.TOKEN_ALL_ACCESS != 0xF01FF {
+ t.Errorf("TOKEN_ALL_ACCESS = %x, want 0xF01FF", syscall.TOKEN_ALL_ACCESS)
+ }
+}
diff --git a/src/syscall/types_linux.go b/src/syscall/types_linux.go
index 125f69d60e..3c4c2f2cfd 100644
--- a/src/syscall/types_linux.go
+++ b/src/syscall/types_linux.go
@@ -405,6 +405,7 @@ const (
_AT_FDCWD = C.AT_FDCWD
_AT_REMOVEDIR = C.AT_REMOVEDIR
_AT_SYMLINK_NOFOLLOW = C.AT_SYMLINK_NOFOLLOW
+ _AT_EACCESS = C.AT_EACCESS
)
// Terminal handling
diff --git a/src/syscall/zerrors_darwin_386.go b/src/syscall/zerrors_darwin_386.go
index debadaa9ce..776aecbf33 100644
--- a/src/syscall/zerrors_darwin_386.go
+++ b/src/syscall/zerrors_darwin_386.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m32 _const.go
diff --git a/src/syscall/zerrors_darwin_amd64.go b/src/syscall/zerrors_darwin_amd64.go
index d4262ba55a..58799fbde7 100644
--- a/src/syscall/zerrors_darwin_amd64.go
+++ b/src/syscall/zerrors_darwin_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_darwin_arm.go b/src/syscall/zerrors_darwin_arm.go
index a64f3735e2..085cde6e91 100644
--- a/src/syscall/zerrors_darwin_arm.go
+++ b/src/syscall/zerrors_darwin_arm.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_darwin_arm64.go b/src/syscall/zerrors_darwin_arm64.go
index 98f431c4e7..8b433616ee 100644
--- a/src/syscall/zerrors_darwin_arm64.go
+++ b/src/syscall/zerrors_darwin_arm64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_dragonfly_amd64.go b/src/syscall/zerrors_dragonfly_amd64.go
index cf36c44d3c..3434a85d34 100644
--- a/src/syscall/zerrors_dragonfly_amd64.go
+++ b/src/syscall/zerrors_dragonfly_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_freebsd_386.go b/src/syscall/zerrors_freebsd_386.go
index bbad05f069..85786a5b4e 100644
--- a/src/syscall/zerrors_freebsd_386.go
+++ b/src/syscall/zerrors_freebsd_386.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m32 _const.go
diff --git a/src/syscall/zerrors_freebsd_amd64.go b/src/syscall/zerrors_freebsd_amd64.go
index b36125b6d3..b3ebf3d474 100644
--- a/src/syscall/zerrors_freebsd_amd64.go
+++ b/src/syscall/zerrors_freebsd_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_freebsd_arm.go b/src/syscall/zerrors_freebsd_arm.go
index 0c844f1387..29eabb1d2d 100644
--- a/src/syscall/zerrors_freebsd_arm.go
+++ b/src/syscall/zerrors_freebsd_arm.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_linux_386.go b/src/syscall/zerrors_linux_386.go
index d433a4f1a4..53a442d108 100644
--- a/src/syscall/zerrors_linux_386.go
+++ b/src/syscall/zerrors_linux_386.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m32 _const.go
diff --git a/src/syscall/zerrors_linux_amd64.go b/src/syscall/zerrors_linux_amd64.go
index dd86a3b0a1..0b4c60dd4c 100644
--- a/src/syscall/zerrors_linux_amd64.go
+++ b/src/syscall/zerrors_linux_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_linux_arm.go b/src/syscall/zerrors_linux_arm.go
index 2a9c0f93c1..9a8d9e8579 100644
--- a/src/syscall/zerrors_linux_arm.go
+++ b/src/syscall/zerrors_linux_arm.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_linux_arm64.go b/src/syscall/zerrors_linux_arm64.go
index 35d9acefe5..f0caf552b2 100644
--- a/src/syscall/zerrors_linux_arm64.go
+++ b/src/syscall/zerrors_linux_arm64.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_linux_mips.go b/src/syscall/zerrors_linux_mips.go
index 580d66f81b..d3dae6d84a 100644
--- a/src/syscall/zerrors_linux_mips.go
+++ b/src/syscall/zerrors_linux_mips.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_linux_mips64.go b/src/syscall/zerrors_linux_mips64.go
index e6399dd8a0..84c9e8fb6f 100644
--- a/src/syscall/zerrors_linux_mips64.go
+++ b/src/syscall/zerrors_linux_mips64.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs _const.go
diff --git a/src/syscall/zerrors_linux_mips64le.go b/src/syscall/zerrors_linux_mips64le.go
index e6399dd8a0..84c9e8fb6f 100644
--- a/src/syscall/zerrors_linux_mips64le.go
+++ b/src/syscall/zerrors_linux_mips64le.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs _const.go
diff --git a/src/syscall/zerrors_linux_mipsle.go b/src/syscall/zerrors_linux_mipsle.go
index 580d66f81b..d3dae6d84a 100644
--- a/src/syscall/zerrors_linux_mipsle.go
+++ b/src/syscall/zerrors_linux_mipsle.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_linux_ppc64.go b/src/syscall/zerrors_linux_ppc64.go
index 1c769cdc77..f064731ae5 100644
--- a/src/syscall/zerrors_linux_ppc64.go
+++ b/src/syscall/zerrors_linux_ppc64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_linux_ppc64le.go b/src/syscall/zerrors_linux_ppc64le.go
index 73727a4197..41e21a510e 100644
--- a/src/syscall/zerrors_linux_ppc64le.go
+++ b/src/syscall/zerrors_linux_ppc64le.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_linux_s390x.go b/src/syscall/zerrors_linux_s390x.go
index 4c3dbe9fb9..cd1aa161e8 100644
--- a/src/syscall/zerrors_linux_s390x.go
+++ b/src/syscall/zerrors_linux_s390x.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_netbsd_386.go b/src/syscall/zerrors_netbsd_386.go
index 6f32def661..bf1e4a74c3 100644
--- a/src/syscall/zerrors_netbsd_386.go
+++ b/src/syscall/zerrors_netbsd_386.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m32 _const.go
diff --git a/src/syscall/zerrors_netbsd_amd64.go b/src/syscall/zerrors_netbsd_amd64.go
index a6d1701f8c..247e78e6c6 100644
--- a/src/syscall/zerrors_netbsd_amd64.go
+++ b/src/syscall/zerrors_netbsd_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_netbsd_arm.go b/src/syscall/zerrors_netbsd_arm.go
index 7f99279e55..f23cd8693f 100644
--- a/src/syscall/zerrors_netbsd_arm.go
+++ b/src/syscall/zerrors_netbsd_arm.go
@@ -1,5 +1,5 @@
// mkerrors.sh -marm
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -marm _const.go
diff --git a/src/syscall/zerrors_openbsd_386.go b/src/syscall/zerrors_openbsd_386.go
index 5a7cdf2b65..7985abe3f0 100644
--- a/src/syscall/zerrors_openbsd_386.go
+++ b/src/syscall/zerrors_openbsd_386.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m32 _const.go
diff --git a/src/syscall/zerrors_openbsd_amd64.go b/src/syscall/zerrors_openbsd_amd64.go
index 11fc1e3a16..9c4ff2955f 100644
--- a/src/syscall/zerrors_openbsd_amd64.go
+++ b/src/syscall/zerrors_openbsd_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_openbsd_arm.go b/src/syscall/zerrors_openbsd_arm.go
index c49ebcfd03..493a8389f2 100644
--- a/src/syscall/zerrors_openbsd_arm.go
+++ b/src/syscall/zerrors_openbsd_arm.go
@@ -1,5 +1,5 @@
// mkerrors.sh
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- _const.go
diff --git a/src/syscall/zerrors_solaris_amd64.go b/src/syscall/zerrors_solaris_amd64.go
index 62ec81be6b..eba401544a 100644
--- a/src/syscall/zerrors_solaris_amd64.go
+++ b/src/syscall/zerrors_solaris_amd64.go
@@ -1,5 +1,5 @@
// mkerrors.sh -m64
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// Created by cgo -godefs - DO NOT EDIT
// cgo -godefs -- -m64 _const.go
diff --git a/src/syscall/zerrors_windows.go b/src/syscall/zerrors_windows.go
index afdeae2bc6..0a971c7dc0 100644
--- a/src/syscall/zerrors_windows.go
+++ b/src/syscall/zerrors_windows.go
@@ -1,5 +1,5 @@
// mkerrors_windows.sh -m32
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsyscall_darwin_386.go b/src/syscall/zsyscall_darwin_386.go
index fe9129a491..44fc684f7a 100644
--- a/src/syscall/zsyscall_darwin_386.go
+++ b/src/syscall/zsyscall_darwin_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -tags darwin,386 syscall_bsd.go syscall_darwin.go syscall_darwin_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build darwin,386
diff --git a/src/syscall/zsyscall_darwin_amd64.go b/src/syscall/zsyscall_darwin_amd64.go
index 3a08ad3e37..a2a95006a2 100644
--- a/src/syscall/zsyscall_darwin_amd64.go
+++ b/src/syscall/zsyscall_darwin_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags darwin,amd64 syscall_bsd.go syscall_darwin.go syscall_darwin_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build darwin,amd64
diff --git a/src/syscall/zsyscall_darwin_arm.go b/src/syscall/zsyscall_darwin_arm.go
index c845cfa67f..419fd3ab1c 100644
--- a/src/syscall/zsyscall_darwin_arm.go
+++ b/src/syscall/zsyscall_darwin_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -tags darwin,arm syscall_bsd.go syscall_darwin.go syscall_darwin_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build darwin,arm
diff --git a/src/syscall/zsyscall_darwin_arm64.go b/src/syscall/zsyscall_darwin_arm64.go
index 66ffa33631..1807559399 100644
--- a/src/syscall/zsyscall_darwin_arm64.go
+++ b/src/syscall/zsyscall_darwin_arm64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags darwin,arm64 syscall_bsd.go syscall_darwin.go syscall_darwin_arm64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build darwin,arm64
diff --git a/src/syscall/zsyscall_dragonfly_amd64.go b/src/syscall/zsyscall_dragonfly_amd64.go
index 6154acfa42..578b5a3e9e 100644
--- a/src/syscall/zsyscall_dragonfly_amd64.go
+++ b/src/syscall/zsyscall_dragonfly_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -dragonfly -tags dragonfly,amd64 syscall_bsd.go syscall_dragonfly.go syscall_dragonfly_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build dragonfly,amd64
diff --git a/src/syscall/zsyscall_freebsd_386.go b/src/syscall/zsyscall_freebsd_386.go
index 81bc754d51..451da4d6fe 100644
--- a/src/syscall/zsyscall_freebsd_386.go
+++ b/src/syscall/zsyscall_freebsd_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -tags freebsd,386 syscall_bsd.go syscall_freebsd.go syscall_freebsd_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build freebsd,386
diff --git a/src/syscall/zsyscall_freebsd_amd64.go b/src/syscall/zsyscall_freebsd_amd64.go
index 1061bb4e01..0312ca347c 100644
--- a/src/syscall/zsyscall_freebsd_amd64.go
+++ b/src/syscall/zsyscall_freebsd_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags freebsd,amd64 syscall_bsd.go syscall_freebsd.go syscall_freebsd_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build freebsd,amd64
diff --git a/src/syscall/zsyscall_freebsd_arm.go b/src/syscall/zsyscall_freebsd_arm.go
index 1cec7f89f6..fcb0733774 100644
--- a/src/syscall/zsyscall_freebsd_arm.go
+++ b/src/syscall/zsyscall_freebsd_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -arm -tags freebsd,arm syscall_bsd.go syscall_freebsd.go syscall_freebsd_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build freebsd,arm
diff --git a/src/syscall/zsyscall_linux_386.go b/src/syscall/zsyscall_linux_386.go
index 951bf9ad48..ef79b3e3e2 100644
--- a/src/syscall/zsyscall_linux_386.go
+++ b/src/syscall/zsyscall_linux_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -tags linux,386 syscall_linux.go syscall_linux_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,386
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_amd64.go b/src/syscall/zsyscall_linux_amd64.go
index 55e7edd9e8..b6638269be 100644
--- a/src/syscall/zsyscall_linux_amd64.go
+++ b/src/syscall/zsyscall_linux_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,amd64 syscall_linux.go syscall_linux_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,amd64
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_arm.go b/src/syscall/zsyscall_linux_arm.go
index 40ee288827..216924ff20 100644
--- a/src/syscall/zsyscall_linux_arm.go
+++ b/src/syscall/zsyscall_linux_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -arm -tags linux,arm syscall_linux.go syscall_linux_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,arm
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_arm64.go b/src/syscall/zsyscall_linux_arm64.go
index 59d445cc1c..f2dffa4bac 100644
--- a/src/syscall/zsyscall_linux_arm64.go
+++ b/src/syscall/zsyscall_linux_arm64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,arm64 syscall_linux.go syscall_linux_arm64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,arm64
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_mips.go b/src/syscall/zsyscall_linux_mips.go
index d304dd784c..72eabac8ec 100644
--- a/src/syscall/zsyscall_linux_mips.go
+++ b/src/syscall/zsyscall_linux_mips.go
@@ -1,5 +1,5 @@
// mksyscall.pl -b32 -arm -tags linux,mips syscall_linux.go syscall_linux_mipsx.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,mips
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off>>32), uintptr(off), uintptr(len>>32), uintptr(len))
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getpid() (pid int) {
- r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0)
pid = int(r0)
return
}
@@ -492,7 +492,7 @@ func Getpid() (pid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getppid() (ppid int) {
- r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
@@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Gettid() (tid int) {
- r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
@@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
- r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0)
oldmask = int(r0)
return
}
@@ -1169,7 +1169,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getegid() (egid int) {
- r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
@@ -1177,7 +1177,7 @@ func Getegid() (egid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Geteuid() (euid int) {
- r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
@@ -1185,7 +1185,7 @@ func Geteuid() (euid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getgid() (gid int) {
- r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
@@ -1193,7 +1193,7 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
diff --git a/src/syscall/zsyscall_linux_mips64.go b/src/syscall/zsyscall_linux_mips64.go
index 83ad1a028e..4180ed1908 100644
--- a/src/syscall/zsyscall_linux_mips64.go
+++ b/src/syscall/zsyscall_linux_mips64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,mips64 syscall_linux.go syscall_linux_mips64x.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,mips64
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getpid() (pid int) {
- r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0)
pid = int(r0)
return
}
@@ -492,7 +492,7 @@ func Getpid() (pid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getppid() (ppid int) {
- r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
@@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Gettid() (tid int) {
- r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
@@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
- r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0)
oldmask = int(r0)
return
}
@@ -1179,7 +1179,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getegid() (egid int) {
- r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
@@ -1187,7 +1187,7 @@ func Getegid() (egid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Geteuid() (euid int) {
- r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
@@ -1195,7 +1195,7 @@ func Geteuid() (euid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getgid() (gid int) {
- r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
@@ -1213,7 +1213,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
diff --git a/src/syscall/zsyscall_linux_mips64le.go b/src/syscall/zsyscall_linux_mips64le.go
index 331e1c89d6..3b4b5da539 100644
--- a/src/syscall/zsyscall_linux_mips64le.go
+++ b/src/syscall/zsyscall_linux_mips64le.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,mips64le syscall_linux.go syscall_linux_mips64x.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,mips64le
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getpid() (pid int) {
- r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0)
pid = int(r0)
return
}
@@ -492,7 +492,7 @@ func Getpid() (pid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getppid() (ppid int) {
- r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
@@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Gettid() (tid int) {
- r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
@@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
- r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0)
oldmask = int(r0)
return
}
@@ -1179,7 +1179,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getegid() (egid int) {
- r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
@@ -1187,7 +1187,7 @@ func Getegid() (egid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Geteuid() (euid int) {
- r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
@@ -1195,7 +1195,7 @@ func Geteuid() (euid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getgid() (gid int) {
- r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
@@ -1213,7 +1213,7 @@ func Getrlimit(resource int, rlim *Rlimit) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
diff --git a/src/syscall/zsyscall_linux_mipsle.go b/src/syscall/zsyscall_linux_mipsle.go
index 363e3a734f..7114093a11 100644
--- a/src/syscall/zsyscall_linux_mipsle.go
+++ b/src/syscall/zsyscall_linux_mipsle.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -arm -tags linux,mipsle syscall_linux.go syscall_linux_mipsx.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,mipsle
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(off>>32), uintptr(len), uintptr(len>>32))
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
@@ -484,7 +484,7 @@ func Getpgid(pid int) (pgid int, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getpid() (pid int) {
- r0, _, _ := RawSyscall(SYS_GETPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPID, 0, 0, 0)
pid = int(r0)
return
}
@@ -492,7 +492,7 @@ func Getpid() (pid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getppid() (ppid int) {
- r0, _, _ := RawSyscall(SYS_GETPPID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETPPID, 0, 0, 0)
ppid = int(r0)
return
}
@@ -521,7 +521,7 @@ func Getrusage(who int, rusage *Rusage) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Gettid() (tid int) {
- r0, _, _ := RawSyscall(SYS_GETTID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETTID, 0, 0, 0)
tid = int(r0)
return
}
@@ -928,7 +928,7 @@ func Times(tms *Tms) (ticks uintptr, err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Umask(mask int) (oldmask int) {
- r0, _, _ := RawSyscall(SYS_UMASK, uintptr(mask), 0, 0)
+ r0, _ := rawSyscallNoError(SYS_UMASK, uintptr(mask), 0, 0)
oldmask = int(r0)
return
}
@@ -1169,7 +1169,7 @@ func Ftruncate(fd int, length int64) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getegid() (egid int) {
- r0, _, _ := RawSyscall(SYS_GETEGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEGID, 0, 0, 0)
egid = int(r0)
return
}
@@ -1177,7 +1177,7 @@ func Getegid() (egid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Geteuid() (euid int) {
- r0, _, _ := RawSyscall(SYS_GETEUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETEUID, 0, 0, 0)
euid = int(r0)
return
}
@@ -1185,7 +1185,7 @@ func Geteuid() (euid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getgid() (gid int) {
- r0, _, _ := RawSyscall(SYS_GETGID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETGID, 0, 0, 0)
gid = int(r0)
return
}
@@ -1193,7 +1193,7 @@ func Getgid() (gid int) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
func Getuid() (uid int) {
- r0, _, _ := RawSyscall(SYS_GETUID, 0, 0, 0)
+ r0, _ := rawSyscallNoError(SYS_GETUID, 0, 0, 0)
uid = int(r0)
return
}
diff --git a/src/syscall/zsyscall_linux_ppc64.go b/src/syscall/zsyscall_linux_ppc64.go
index 6f0e09e63a..b76944e96c 100644
--- a/src/syscall/zsyscall_linux_ppc64.go
+++ b/src/syscall/zsyscall_linux_ppc64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,ppc64 syscall_linux.go syscall_linux_ppc64x.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,ppc64
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_ppc64le.go b/src/syscall/zsyscall_linux_ppc64le.go
index 6202e79b36..613793b0bf 100644
--- a/src/syscall/zsyscall_linux_ppc64le.go
+++ b/src/syscall/zsyscall_linux_ppc64le.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,ppc64le syscall_linux.go syscall_linux_ppc64x.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,ppc64le
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_linux_s390x.go b/src/syscall/zsyscall_linux_s390x.go
index 1020c8ee60..7c63c3db58 100644
--- a/src/syscall/zsyscall_linux_s390x.go
+++ b/src/syscall/zsyscall_linux_s390x.go
@@ -1,5 +1,5 @@
// mksyscall.pl -tags linux,s390x syscall_linux.go syscall_linux_s390x.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build linux,s390x
@@ -9,6 +9,36 @@ import "unsafe"
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+func faccessat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
+func fchmodat(dirfd int, path string, mode uint32) (err error) {
+ var _p0 *byte
+ _p0, err = BytePtrFromString(path)
+ if err != nil {
+ return
+ }
+ _, _, e1 := Syscall(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
+ if e1 != 0 {
+ err = errnoErr(e1)
+ }
+ return
+}
+
+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
+
func linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(oldpath)
@@ -339,21 +369,6 @@ func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FACCESSAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
_, _, e1 := Syscall6(SYS_FALLOCATE, uintptr(fd), uintptr(mode), uintptr(off), uintptr(len), 0, 0)
if e1 != 0 {
@@ -384,21 +399,6 @@ func Fchmod(fd int, mode uint32) (err error) {
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
- var _p0 *byte
- _p0, err = BytePtrFromString(path)
- if err != nil {
- return
- }
- _, _, e1 := Syscall6(SYS_FCHMODAT, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode), uintptr(flags), 0, 0)
- if e1 != 0 {
- err = errnoErr(e1)
- }
- return
-}
-
-// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
-
func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
var _p0 *byte
_p0, err = BytePtrFromString(path)
diff --git a/src/syscall/zsyscall_nacl_386.go b/src/syscall/zsyscall_nacl_386.go
index 1feab5702f..fb286ba4d3 100644
--- a/src/syscall/zsyscall_nacl_386.go
+++ b/src/syscall/zsyscall_nacl_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -nacl -tags nacl,386 syscall_nacl.go syscall_nacl_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build nacl,386
diff --git a/src/syscall/zsyscall_nacl_amd64p32.go b/src/syscall/zsyscall_nacl_amd64p32.go
index 880fa45d1d..799b24dea3 100644
--- a/src/syscall/zsyscall_nacl_amd64p32.go
+++ b/src/syscall/zsyscall_nacl_amd64p32.go
@@ -1,5 +1,5 @@
// mksyscall.pl -nacl -tags nacl,amd64p32 syscall_nacl.go syscall_nacl_amd64p32.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build nacl,amd64p32
diff --git a/src/syscall/zsyscall_nacl_arm.go b/src/syscall/zsyscall_nacl_arm.go
index 4c852c531a..d06d02c297 100644
--- a/src/syscall/zsyscall_nacl_arm.go
+++ b/src/syscall/zsyscall_nacl_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -nacl -arm -tags nacl,arm syscall_nacl.go syscall_nacl_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build nacl,arm
diff --git a/src/syscall/zsyscall_netbsd_386.go b/src/syscall/zsyscall_netbsd_386.go
index aeb8bd6bc4..7e0210081e 100644
--- a/src/syscall/zsyscall_netbsd_386.go
+++ b/src/syscall/zsyscall_netbsd_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -netbsd -tags netbsd,386 syscall_bsd.go syscall_netbsd.go syscall_netbsd_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build netbsd,386
diff --git a/src/syscall/zsyscall_netbsd_amd64.go b/src/syscall/zsyscall_netbsd_amd64.go
index a4de164382..e9ee790501 100644
--- a/src/syscall/zsyscall_netbsd_amd64.go
+++ b/src/syscall/zsyscall_netbsd_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -netbsd -tags netbsd,amd64 syscall_bsd.go syscall_netbsd.go syscall_netbsd_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build netbsd,amd64
diff --git a/src/syscall/zsyscall_netbsd_arm.go b/src/syscall/zsyscall_netbsd_arm.go
index 1b33ea1918..37438b020b 100644
--- a/src/syscall/zsyscall_netbsd_arm.go
+++ b/src/syscall/zsyscall_netbsd_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -netbsd -arm -tags netbsd,arm syscall_bsd.go syscall_netbsd.go syscall_netbsd_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build netbsd,arm
diff --git a/src/syscall/zsyscall_openbsd_386.go b/src/syscall/zsyscall_openbsd_386.go
index 8fc96e0b68..decd169f0d 100644
--- a/src/syscall/zsyscall_openbsd_386.go
+++ b/src/syscall/zsyscall_openbsd_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -openbsd -tags openbsd,386 syscall_bsd.go syscall_openbsd.go syscall_openbsd_386.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build openbsd,386
diff --git a/src/syscall/zsyscall_openbsd_amd64.go b/src/syscall/zsyscall_openbsd_amd64.go
index 50bd41083b..f7390390e0 100644
--- a/src/syscall/zsyscall_openbsd_amd64.go
+++ b/src/syscall/zsyscall_openbsd_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -openbsd -tags openbsd,amd64 syscall_bsd.go syscall_openbsd.go syscall_openbsd_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build openbsd,amd64
diff --git a/src/syscall/zsyscall_openbsd_arm.go b/src/syscall/zsyscall_openbsd_arm.go
index 99be8d4e93..dce0a540e6 100644
--- a/src/syscall/zsyscall_openbsd_arm.go
+++ b/src/syscall/zsyscall_openbsd_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -openbsd -arm -tags openbsd,arm syscall_bsd.go syscall_openbsd.go syscall_openbsd_arm.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build openbsd,arm
diff --git a/src/syscall/zsyscall_plan9_386.go b/src/syscall/zsyscall_plan9_386.go
index 502716df0a..998c6c555e 100644
--- a/src/syscall/zsyscall_plan9_386.go
+++ b/src/syscall/zsyscall_plan9_386.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 -tags plan9,386 syscall_plan9.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build plan9,386
diff --git a/src/syscall/zsyscall_plan9_amd64.go b/src/syscall/zsyscall_plan9_amd64.go
index d3e8b31cf1..02a28294ea 100644
--- a/src/syscall/zsyscall_plan9_amd64.go
+++ b/src/syscall/zsyscall_plan9_amd64.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 -tags plan9,amd64 syscall_plan9.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build plan9,amd64
diff --git a/src/syscall/zsyscall_plan9_arm.go b/src/syscall/zsyscall_plan9_arm.go
index 3c0d25b455..449823976d 100644
--- a/src/syscall/zsyscall_plan9_arm.go
+++ b/src/syscall/zsyscall_plan9_arm.go
@@ -1,5 +1,5 @@
// mksyscall.pl -l32 -plan9 -tags plan9,arm syscall_plan9.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build plan9,arm
diff --git a/src/syscall/zsyscall_solaris_amd64.go b/src/syscall/zsyscall_solaris_amd64.go
index 4bb8318158..ecd37902e0 100644
--- a/src/syscall/zsyscall_solaris_amd64.go
+++ b/src/syscall/zsyscall_solaris_amd64.go
@@ -1,5 +1,5 @@
// mksyscall_solaris.pl -tags solaris,amd64 syscall_solaris.go syscall_solaris_amd64.go
-// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build solaris,amd64
diff --git a/src/syscall/zsyscall_windows.go b/src/syscall/zsyscall_windows.go
index 1626c305fc..de2d4f3adb 100644
--- a/src/syscall/zsyscall_windows.go
+++ b/src/syscall/zsyscall_windows.go
@@ -1,4 +1,4 @@
-// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT
+// Code generated by 'go generate'; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysctl_openbsd.go b/src/syscall/zsysctl_openbsd.go
index 923b2c29fb..045930d6f9 100644
--- a/src/syscall/zsysctl_openbsd.go
+++ b/src/syscall/zsysctl_openbsd.go
@@ -1,5 +1,5 @@
// mksysctl_openbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_darwin_386.go b/src/syscall/zsysnum_darwin_386.go
index c6f8342841..407ae483c3 100644
--- a/src/syscall/zsysnum_darwin_386.go
+++ b/src/syscall/zsysnum_darwin_386.go
@@ -1,5 +1,5 @@
// mksysnum_darwin.pl /usr/include/sys/syscall.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build 386,darwin
diff --git a/src/syscall/zsysnum_darwin_amd64.go b/src/syscall/zsysnum_darwin_amd64.go
index 7189abe3db..a2331bee8a 100644
--- a/src/syscall/zsysnum_darwin_amd64.go
+++ b/src/syscall/zsysnum_darwin_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_darwin.pl /usr/include/sys/syscall.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,darwin
diff --git a/src/syscall/zsysnum_darwin_arm.go b/src/syscall/zsysnum_darwin_arm.go
index 1d76861204..b82f0408ca 100644
--- a/src/syscall/zsysnum_darwin_arm.go
+++ b/src/syscall/zsysnum_darwin_arm.go
@@ -1,5 +1,5 @@
// mksysnum_darwin.pl /usr/include/sys/syscall.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm,darwin
diff --git a/src/syscall/zsysnum_darwin_arm64.go b/src/syscall/zsysnum_darwin_arm64.go
index ddf8e83c87..9548717945 100644
--- a/src/syscall/zsysnum_darwin_arm64.go
+++ b/src/syscall/zsysnum_darwin_arm64.go
@@ -1,5 +1,5 @@
// mksysnum_darwin.pl /usr/include/sys/syscall.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm64,darwin
diff --git a/src/syscall/zsysnum_dragonfly_amd64.go b/src/syscall/zsysnum_dragonfly_amd64.go
index bc535f26bf..9ce11f5899 100644
--- a/src/syscall/zsysnum_dragonfly_amd64.go
+++ b/src/syscall/zsysnum_dragonfly_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_dragonfly.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,dragonfly
diff --git a/src/syscall/zsysnum_freebsd_386.go b/src/syscall/zsysnum_freebsd_386.go
index d0e403acea..bb6e9d7ac3 100644
--- a/src/syscall/zsysnum_freebsd_386.go
+++ b/src/syscall/zsysnum_freebsd_386.go
@@ -1,5 +1,5 @@
// mksysnum_freebsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build 386,freebsd
diff --git a/src/syscall/zsysnum_freebsd_amd64.go b/src/syscall/zsysnum_freebsd_amd64.go
index 2fa4d211d3..f5d81abc51 100644
--- a/src/syscall/zsysnum_freebsd_amd64.go
+++ b/src/syscall/zsysnum_freebsd_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_freebsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,freebsd
diff --git a/src/syscall/zsysnum_freebsd_arm.go b/src/syscall/zsysnum_freebsd_arm.go
index d2caa8f2ad..006b49c245 100644
--- a/src/syscall/zsysnum_freebsd_arm.go
+++ b/src/syscall/zsysnum_freebsd_arm.go
@@ -1,5 +1,5 @@
// mksysnum_freebsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm,freebsd
diff --git a/src/syscall/zsysnum_linux_386.go b/src/syscall/zsysnum_linux_386.go
index c277ed9a25..6bcd22185e 100644
--- a/src/syscall/zsysnum_linux_386.go
+++ b/src/syscall/zsysnum_linux_386.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd_32.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build 386,linux
diff --git a/src/syscall/zsysnum_linux_amd64.go b/src/syscall/zsysnum_linux_amd64.go
index 978a4d3c3d..70ca68639f 100644
--- a/src/syscall/zsysnum_linux_amd64.go
+++ b/src/syscall/zsysnum_linux_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd_64.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,linux
diff --git a/src/syscall/zsysnum_linux_arm.go b/src/syscall/zsysnum_linux_arm.go
index 5061cbab2b..39ddc6536b 100644
--- a/src/syscall/zsysnum_linux_arm.go
+++ b/src/syscall/zsysnum_linux_arm.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm,linux
diff --git a/src/syscall/zsysnum_linux_arm64.go b/src/syscall/zsysnum_linux_arm64.go
index d53712c681..22a88b4dfe 100644
--- a/src/syscall/zsysnum_linux_arm64.go
+++ b/src/syscall/zsysnum_linux_arm64.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm-generic/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm64,linux
diff --git a/src/syscall/zsysnum_linux_mips.go b/src/syscall/zsysnum_linux_mips.go
index f99ca56c02..6c301f3529 100644
--- a/src/syscall/zsysnum_linux_mips.go
+++ b/src/syscall/zsysnum_linux_mips.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_linux_mips64.go b/src/syscall/zsysnum_linux_mips64.go
index a51ecfe38c..c690ef1952 100644
--- a/src/syscall/zsysnum_linux_mips64.go
+++ b/src/syscall/zsysnum_linux_mips64.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_linux_mips64le.go b/src/syscall/zsysnum_linux_mips64le.go
index a51ecfe38c..c690ef1952 100644
--- a/src/syscall/zsysnum_linux_mips64le.go
+++ b/src/syscall/zsysnum_linux_mips64le.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_linux_mipsle.go b/src/syscall/zsysnum_linux_mipsle.go
index f99ca56c02..6c301f3529 100644
--- a/src/syscall/zsysnum_linux_mipsle.go
+++ b/src/syscall/zsysnum_linux_mipsle.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/mips-linux-gnu/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_linux_ppc64.go b/src/syscall/zsysnum_linux_ppc64.go
index 82d253a1ab..5882a7c058 100644
--- a/src/syscall/zsysnum_linux_ppc64.go
+++ b/src/syscall/zsysnum_linux_ppc64.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build ppc64,linux
diff --git a/src/syscall/zsysnum_linux_ppc64le.go b/src/syscall/zsysnum_linux_ppc64le.go
index 3af4e83822..4fb3f6cd29 100644
--- a/src/syscall/zsysnum_linux_ppc64le.go
+++ b/src/syscall/zsysnum_linux_ppc64le.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/powerpc64le-linux-gnu/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build ppc64le,linux
diff --git a/src/syscall/zsysnum_linux_s390x.go b/src/syscall/zsysnum_linux_s390x.go
index 2cb7dbbc0d..51557e2487 100644
--- a/src/syscall/zsysnum_linux_s390x.go
+++ b/src/syscall/zsysnum_linux_s390x.go
@@ -1,5 +1,5 @@
// mksysnum_linux.pl /usr/include/asm/unistd.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/zsysnum_netbsd_386.go b/src/syscall/zsysnum_netbsd_386.go
index c8af210082..514d1f8cfd 100644
--- a/src/syscall/zsysnum_netbsd_386.go
+++ b/src/syscall/zsysnum_netbsd_386.go
@@ -1,5 +1,5 @@
// mksysnum_netbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build 386,netbsd
diff --git a/src/syscall/zsysnum_netbsd_amd64.go b/src/syscall/zsysnum_netbsd_amd64.go
index e342a3ce58..db05c03ecd 100644
--- a/src/syscall/zsysnum_netbsd_amd64.go
+++ b/src/syscall/zsysnum_netbsd_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_netbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,netbsd
diff --git a/src/syscall/zsysnum_netbsd_arm.go b/src/syscall/zsysnum_netbsd_arm.go
index 1f5b569b8f..9a10a4383a 100644
--- a/src/syscall/zsysnum_netbsd_arm.go
+++ b/src/syscall/zsysnum_netbsd_arm.go
@@ -1,5 +1,5 @@
// mksysnum_netbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm,netbsd
diff --git a/src/syscall/zsysnum_openbsd_386.go b/src/syscall/zsysnum_openbsd_386.go
index 8262ec5f53..39b9c78288 100644
--- a/src/syscall/zsysnum_openbsd_386.go
+++ b/src/syscall/zsysnum_openbsd_386.go
@@ -1,5 +1,5 @@
// mksysnum_openbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build 386,openbsd
diff --git a/src/syscall/zsysnum_openbsd_amd64.go b/src/syscall/zsysnum_openbsd_amd64.go
index 1b0a52750c..e176c4e23e 100644
--- a/src/syscall/zsysnum_openbsd_amd64.go
+++ b/src/syscall/zsysnum_openbsd_amd64.go
@@ -1,5 +1,5 @@
// mksysnum_openbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build amd64,openbsd
diff --git a/src/syscall/zsysnum_openbsd_arm.go b/src/syscall/zsysnum_openbsd_arm.go
index 3e6b984a85..96bbdb09f5 100644
--- a/src/syscall/zsysnum_openbsd_arm.go
+++ b/src/syscall/zsysnum_openbsd_arm.go
@@ -1,5 +1,5 @@
// mksysnum_openbsd.pl
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
// +build arm,openbsd
diff --git a/src/syscall/zsysnum_plan9.go b/src/syscall/zsysnum_plan9.go
index 07498c4892..432b474905 100644
--- a/src/syscall/zsysnum_plan9.go
+++ b/src/syscall/zsysnum_plan9.go
@@ -1,5 +1,5 @@
// mksysnum_plan9.sh /media/sys/src/libc/9syscall/sys.h
-// MACHINE GENERATED BY THE ABOVE COMMAND; DO NOT EDIT
+// Code generated by the command above; DO NOT EDIT.
package syscall
diff --git a/src/syscall/ztypes_linux_386.go b/src/syscall/ztypes_linux_386.go
index a73c91770f..c92dfad114 100644
--- a/src/syscall/ztypes_linux_386.go
+++ b/src/syscall/ztypes_linux_386.go
@@ -576,6 +576,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_amd64.go b/src/syscall/ztypes_linux_amd64.go
index 4cbd5d899d..623585a639 100644
--- a/src/syscall/ztypes_linux_amd64.go
+++ b/src/syscall/ztypes_linux_amd64.go
@@ -594,6 +594,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_arm.go b/src/syscall/ztypes_linux_arm.go
index 16aa014ada..0c0a94a52f 100644
--- a/src/syscall/ztypes_linux_arm.go
+++ b/src/syscall/ztypes_linux_arm.go
@@ -565,6 +565,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_arm64.go b/src/syscall/ztypes_linux_arm64.go
index e5d669cdba..ea682c4efa 100644
--- a/src/syscall/ztypes_linux_arm64.go
+++ b/src/syscall/ztypes_linux_arm64.go
@@ -572,6 +572,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_mips.go b/src/syscall/ztypes_linux_mips.go
index 7a8d34dfc2..6d42e48d60 100644
--- a/src/syscall/ztypes_linux_mips.go
+++ b/src/syscall/ztypes_linux_mips.go
@@ -571,6 +571,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_mips64.go b/src/syscall/ztypes_linux_mips64.go
index 8c5a0d1d76..397ded1f4d 100644
--- a/src/syscall/ztypes_linux_mips64.go
+++ b/src/syscall/ztypes_linux_mips64.go
@@ -577,6 +577,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_mips64le.go b/src/syscall/ztypes_linux_mips64le.go
index 8c5a0d1d76..397ded1f4d 100644
--- a/src/syscall/ztypes_linux_mips64le.go
+++ b/src/syscall/ztypes_linux_mips64le.go
@@ -577,6 +577,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_mipsle.go b/src/syscall/ztypes_linux_mipsle.go
index 7a8d34dfc2..6d42e48d60 100644
--- a/src/syscall/ztypes_linux_mipsle.go
+++ b/src/syscall/ztypes_linux_mipsle.go
@@ -571,6 +571,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_ppc64.go b/src/syscall/ztypes_linux_ppc64.go
index 087a70d443..3d295390f6 100644
--- a/src/syscall/ztypes_linux_ppc64.go
+++ b/src/syscall/ztypes_linux_ppc64.go
@@ -583,6 +583,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_ppc64le.go b/src/syscall/ztypes_linux_ppc64le.go
index 8412bddbfa..220083d9c5 100644
--- a/src/syscall/ztypes_linux_ppc64le.go
+++ b/src/syscall/ztypes_linux_ppc64le.go
@@ -583,6 +583,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/syscall/ztypes_linux_s390x.go b/src/syscall/ztypes_linux_s390x.go
index 63c4a83b19..2805966774 100644
--- a/src/syscall/ztypes_linux_s390x.go
+++ b/src/syscall/ztypes_linux_s390x.go
@@ -597,6 +597,7 @@ const (
_AT_FDCWD = -0x64
_AT_REMOVEDIR = 0x200
_AT_SYMLINK_NOFOLLOW = 0x100
+ _AT_EACCESS = 0x200
)
type Termios struct {
diff --git a/src/text/template/exec.go b/src/text/template/exec.go
index 8f8b5fe218..214f72d51b 100644
--- a/src/text/template/exec.go
+++ b/src/text/template/exec.go
@@ -252,7 +252,7 @@ func (s *state) walk(dot reflect.Value, node parse.Node) {
// Do not pop variables so they persist until next end.
// Also, if the action declares variables, don't print the result.
val := s.evalPipeline(dot, node.Pipe)
- if len(node.Pipe.Vars) == 0 {
+ if len(node.Pipe.Decl) == 0 {
s.printValue(node, val)
}
case *parse.IfNode:
@@ -339,11 +339,11 @@ func (s *state) walkRange(dot reflect.Value, r *parse.RangeNode) {
mark := s.mark()
oneIteration := func(index, elem reflect.Value) {
// Set top var (lexically the second if there are two) to the element.
- if len(r.Pipe.Vars) > 0 {
+ if len(r.Pipe.Decl) > 0 {
s.setTopVar(1, elem)
}
// Set next var (lexically the first if there are two) to the index.
- if len(r.Pipe.Vars) > 1 {
+ if len(r.Pipe.Decl) > 1 {
s.setTopVar(2, index)
}
s.walk(elem, r.List)
@@ -432,11 +432,11 @@ func (s *state) evalPipeline(dot reflect.Value, pipe *parse.PipeNode) (value ref
value = reflect.ValueOf(value.Interface()) // lovely!
}
}
- for _, variable := range pipe.Vars {
- if pipe.Decl {
- s.push(variable.Ident[0], value)
- } else {
+ for _, variable := range pipe.Decl {
+ if pipe.IsAssign {
s.setVar(variable.Ident[0], value)
+ } else {
+ s.push(variable.Ident[0], value)
}
}
return value
@@ -461,7 +461,7 @@ func (s *state) evalCommand(dot reflect.Value, cmd *parse.CommandNode, final ref
case *parse.PipeNode:
// Parenthesized pipeline. The arguments are all inside the pipeline; final is ignored.
return s.evalPipeline(dot, n)
- case *parse.AssignNode:
+ case *parse.VariableNode:
return s.evalVariableNode(dot, n, cmd.Args, final)
}
s.at(firstWord)
@@ -530,7 +530,7 @@ func (s *state) evalChainNode(dot reflect.Value, chain *parse.ChainNode, args []
return s.evalFieldChain(dot, pipe, chain, chain.Field, args, final)
}
-func (s *state) evalVariableNode(dot reflect.Value, variable *parse.AssignNode, args []parse.Node, final reflect.Value) reflect.Value {
+func (s *state) evalVariableNode(dot reflect.Value, variable *parse.VariableNode, args []parse.Node, final reflect.Value) reflect.Value {
// $x.Field has $x as the first ident, Field as the second. Eval the var, then the fields.
s.at(variable)
value := s.varValue(variable.Ident[0])
@@ -771,7 +771,7 @@ func (s *state) evalArg(dot reflect.Value, typ reflect.Type, n parse.Node) refle
s.errorf("cannot assign nil to %s", typ)
case *parse.FieldNode:
return s.validateType(s.evalFieldNode(dot, arg, []parse.Node{n}, missingVal), typ)
- case *parse.AssignNode:
+ case *parse.VariableNode:
return s.validateType(s.evalVariableNode(dot, arg, nil, missingVal), typ)
case *parse.PipeNode:
return s.validateType(s.evalPipeline(dot, arg), typ)
@@ -889,7 +889,7 @@ func (s *state) evalEmptyInterface(dot reflect.Value, n parse.Node) reflect.Valu
return s.idealConstant(n)
case *parse.StringNode:
return reflect.ValueOf(n.Text)
- case *parse.AssignNode:
+ case *parse.VariableNode:
return s.evalVariableNode(dot, n, nil, missingVal)
case *parse.PipeNode:
return s.evalPipeline(dot, n)
diff --git a/src/text/template/parse/lex.go b/src/text/template/parse/lex.go
index fae8841fb1..fc259f351e 100644
--- a/src/text/template/parse/lex.go
+++ b/src/text/template/parse/lex.go
@@ -42,7 +42,7 @@ const (
itemChar // printable ASCII character; grab bag for comma etc.
itemCharConstant // character constant
itemComplex // complex constant (1+2i); imaginary is just a number
- itemAssign // colon-equals ('=') introducing an assignment
+ itemAssign // equals ('=') introducing an assignment
itemDeclare // colon-equals (':=') introducing a declaration
itemEOF
itemField // alphanumeric identifier starting with '.'
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 0bb96fc2e9..dca83dacce 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -144,15 +144,15 @@ func (t *TextNode) Copy() Node {
type PipeNode struct {
NodeType
Pos
- tr *Tree
- Line int // The line number in the input. Deprecated: Kept for compatibility.
- Decl bool // The variables are being declared, not assigned
- Vars []*AssignNode // Variables in lexical order.
- Cmds []*CommandNode // The commands in lexical order.
+ tr *Tree
+ Line int // The line number in the input. Deprecated: Kept for compatibility.
+ IsAssign bool // The variables are being assigned, not declared.
+ Decl []*VariableNode // Variables in lexical order.
+ Cmds []*CommandNode // The commands in lexical order.
}
-func (t *Tree) newPipeline(pos Pos, line int, vars []*AssignNode) *PipeNode {
- return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Vars: vars}
+func (t *Tree) newPipeline(pos Pos, line int, vars []*VariableNode) *PipeNode {
+ return &PipeNode{tr: t, NodeType: NodePipe, Pos: pos, Line: line, Decl: vars}
}
func (p *PipeNode) append(command *CommandNode) {
@@ -161,8 +161,8 @@ func (p *PipeNode) append(command *CommandNode) {
func (p *PipeNode) String() string {
s := ""
- if len(p.Vars) > 0 {
- for i, v := range p.Vars {
+ if len(p.Decl) > 0 {
+ for i, v := range p.Decl {
if i > 0 {
s += ", "
}
@@ -187,12 +187,12 @@ func (p *PipeNode) CopyPipe() *PipeNode {
if p == nil {
return p
}
- var vars []*AssignNode
- for _, d := range p.Vars {
- vars = append(vars, d.Copy().(*AssignNode))
+ var vars []*VariableNode
+ for _, d := range p.Decl {
+ vars = append(vars, d.Copy().(*VariableNode))
}
n := p.tr.newPipeline(p.Pos, p.Line, vars)
- n.Decl = p.Decl
+ n.IsAssign = p.IsAssign
for _, c := range p.Cmds {
n.append(c.Copy().(*CommandNode))
}
@@ -321,18 +321,18 @@ func (i *IdentifierNode) Copy() Node {
// AssignNode holds a list of variable names, possibly with chained field
// accesses. The dollar sign is part of the (first) name.
-type AssignNode struct {
+type VariableNode struct {
NodeType
Pos
tr *Tree
Ident []string // Variable name and fields in lexical order.
}
-func (t *Tree) newVariable(pos Pos, ident string) *AssignNode {
- return &AssignNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
+func (t *Tree) newVariable(pos Pos, ident string) *VariableNode {
+ return &VariableNode{tr: t, NodeType: NodeVariable, Pos: pos, Ident: strings.Split(ident, ".")}
}
-func (v *AssignNode) String() string {
+func (v *VariableNode) String() string {
s := ""
for i, id := range v.Ident {
if i > 0 {
@@ -343,12 +343,12 @@ func (v *AssignNode) String() string {
return s
}
-func (v *AssignNode) tree() *Tree {
+func (v *VariableNode) tree() *Tree {
return v.tr
}
-func (v *AssignNode) Copy() Node {
- return &AssignNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
+func (v *VariableNode) Copy() Node {
+ return &VariableNode{tr: v.tr, NodeType: NodeVariable, Pos: v.Pos, Ident: append([]string{}, v.Ident...)}
}
// DotNode holds the special identifier '.'.
diff --git a/src/text/template/parse/parse.go b/src/text/template/parse/parse.go
index 34dc41c620..cb9b44e9da 100644
--- a/src/text/template/parse/parse.go
+++ b/src/text/template/parse/parse.go
@@ -384,7 +384,7 @@ func (t *Tree) action() (n Node) {
// declarations? command ('|' command)*
func (t *Tree) pipeline(context string) (pipe *PipeNode) {
decl := false
- var vars []*AssignNode
+ var vars []*VariableNode
token := t.peekNonSpace()
pos := token.pos
// Are there declarations or assignments?
@@ -422,7 +422,7 @@ func (t *Tree) pipeline(context string) (pipe *PipeNode) {
break
}
pipe = t.newPipeline(pos, token.line, vars)
- pipe.Decl = decl
+ pipe.IsAssign = !decl
for {
switch token := t.nextNonSpace(); token.typ {
case itemRightDelim, itemRightParen:
diff --git a/src/time/zoneinfo_abbrs_windows.go b/src/time/zoneinfo_abbrs_windows.go
index 76ee528388..5411325ffe 100644
--- a/src/time/zoneinfo_abbrs_windows.go
+++ b/src/time/zoneinfo_abbrs_windows.go
@@ -16,10 +16,11 @@ var abbrs = map[string]abbr{
"Egypt Standard Time": {"EET", "EET"}, // Africa/Cairo
"Morocco Standard Time": {"WET", "WEST"}, // Africa/Casablanca
"South Africa Standard Time": {"SAST", "SAST"}, // Africa/Johannesburg
+ "Sudan Standard Time": {"CAT", "CAT"}, // Africa/Khartoum
"W. Central Africa Standard Time": {"WAT", "WAT"}, // Africa/Lagos
"E. Africa Standard Time": {"EAT", "EAT"}, // Africa/Nairobi
"Libya Standard Time": {"EET", "EET"}, // Africa/Tripoli
- "Namibia Standard Time": {"WAT", "WAST"}, // Africa/Windhoek
+ "Namibia Standard Time": {"CAT", "CAT"}, // Africa/Windhoek
"Aleutian Standard Time": {"HST", "HDT"}, // America/Adak
"Alaskan Standard Time": {"AKST", "AKDT"}, // America/Anchorage
"Tocantins Standard Time": {"-03", "-03"}, // America/Araguaina
@@ -35,7 +36,7 @@ var abbrs = map[string]abbr{
"Central Brazilian Standard Time": {"-04", "-03"}, // America/Cuiaba
"Mountain Standard Time": {"MST", "MDT"}, // America/Denver
"Greenland Standard Time": {"-03", "-02"}, // America/Godthab
- "Turks And Caicos Standard Time": {"AST", "AST"}, // America/Grand_Turk
+ "Turks And Caicos Standard Time": {"AST", "EDT"}, // America/Grand_Turk
"Central America Standard Time": {"CST", "CST"}, // America/Guatemala
"Atlantic Standard Time": {"AST", "ADT"}, // America/Halifax
"Cuba Standard Time": {"CST", "CDT"}, // America/Havana
@@ -130,7 +131,7 @@ var abbrs = map[string]abbr{
"Russian Standard Time": {"MSK", "MSK"}, // Europe/Moscow
"Romance Standard Time": {"CET", "CEST"}, // Europe/Paris
"Russia Time Zone 3": {"+04", "+04"}, // Europe/Samara
- "Saratov Standard Time": {"+03", "+04"}, // Europe/Saratov
+ "Saratov Standard Time": {"+04", "+04"}, // Europe/Saratov
"Central European Standard Time": {"CET", "CEST"}, // Europe/Warsaw
"Mauritius Standard Time": {"+04", "+04"}, // Indian/Mauritius
"Samoa Standard Time": {"+13", "+14"}, // Pacific/Apia
@@ -145,5 +146,5 @@ var abbrs = map[string]abbr{
"Marquesas Standard Time": {"-0930", "-0930"}, // Pacific/Marquesas
"Norfolk Standard Time": {"+11", "+11"}, // Pacific/Norfolk
"West Pacific Standard Time": {"+10", "+10"}, // Pacific/Port_Moresby
- "Tonga Standard Time": {"+13", "+14"}, // Pacific/Tongatapu
+ "Tonga Standard Time": {"+13", "+13"}, // Pacific/Tongatapu
}
diff --git a/src/unicode/letter.go b/src/unicode/letter.go
index 4d9fc67165..8be9a7b7c9 100644
--- a/src/unicode/letter.go
+++ b/src/unicode/letter.go
@@ -206,9 +206,10 @@ func IsTitle(r rune) bool {
}
// to maps the rune using the specified case mapping.
-func to(_case int, r rune, caseRange []CaseRange) rune {
+// It additionally reports whether caseRange contained a mapping for r.
+func to(_case int, r rune, caseRange []CaseRange) (mappedRune rune, foundMapping bool) {
if _case < 0 || MaxCase <= _case {
- return ReplacementChar // as reasonable an error as any
+ return ReplacementChar, false // as reasonable an error as any
}
// binary search over ranges
lo := 0
@@ -229,9 +230,9 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
// bit in the sequence offset.
// The constants UpperCase and TitleCase are even while LowerCase
// is odd so we take the low bit from _case.
- return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1))
+ return rune(cr.Lo) + ((r-rune(cr.Lo))&^1 | rune(_case&1)), true
}
- return r + delta
+ return r + delta, true
}
if r < rune(cr.Lo) {
hi = m
@@ -239,12 +240,13 @@ func to(_case int, r rune, caseRange []CaseRange) rune {
lo = m + 1
}
}
- return r
+ return r, false
}
// To maps the rune to the specified case: UpperCase, LowerCase, or TitleCase.
func To(_case int, r rune) rune {
- return to(_case, r, CaseRanges)
+ r, _ = to(_case, r, CaseRanges)
+ return r
}
// ToUpper maps the rune to upper case.
@@ -282,8 +284,8 @@ func ToTitle(r rune) rune {
// ToUpper maps the rune to upper case giving priority to the special mapping.
func (special SpecialCase) ToUpper(r rune) rune {
- r1 := to(UpperCase, r, []CaseRange(special))
- if r1 == r {
+ r1, hadMapping := to(UpperCase, r, []CaseRange(special))
+ if r1 == r && !hadMapping {
r1 = ToUpper(r)
}
return r1
@@ -291,8 +293,8 @@ func (special SpecialCase) ToUpper(r rune) rune {
// ToTitle maps the rune to title case giving priority to the special mapping.
func (special SpecialCase) ToTitle(r rune) rune {
- r1 := to(TitleCase, r, []CaseRange(special))
- if r1 == r {
+ r1, hadMapping := to(TitleCase, r, []CaseRange(special))
+ if r1 == r && !hadMapping {
r1 = ToTitle(r)
}
return r1
@@ -300,8 +302,8 @@ func (special SpecialCase) ToTitle(r rune) rune {
// ToLower maps the rune to lower case giving priority to the special mapping.
func (special SpecialCase) ToLower(r rune) rune {
- r1 := to(LowerCase, r, []CaseRange(special))
- if r1 == r {
+ r1, hadMapping := to(LowerCase, r, []CaseRange(special))
+ if r1 == r && !hadMapping {
r1 = ToLower(r)
}
return r1
diff --git a/src/unicode/letter_test.go b/src/unicode/letter_test.go
index 3fe72ff13d..19ee535d57 100644
--- a/src/unicode/letter_test.go
+++ b/src/unicode/letter_test.go
@@ -9,6 +9,7 @@ import (
"fmt"
"runtime"
"sort"
+ "strings"
"testing"
. "unicode"
)
@@ -551,3 +552,14 @@ func TestLatinOffset(t *testing.T) {
}
}
}
+
+func TestSpecialCaseNoMapping(t *testing.T) {
+ // Issue 25636
+ // no change for rune 'A', zero delta, under upper/lower/title case change.
+ var noChangeForCapitalA = CaseRange{'A', 'A', [MaxCase]rune{0, 0, 0}}
+ got := strings.ToLowerSpecial(SpecialCase([]CaseRange{noChangeForCapitalA}), "ABC")
+ want := "Abc"
+ if got != want {
+ t.Errorf("got %q; want %q", got, want)
+ }
+}
diff --git a/test/fixedbugs/issue18640.go b/test/fixedbugs/issue18640.go
index c4f948b706..60abd31f76 100644
--- a/test/fixedbugs/issue18640.go
+++ b/test/fixedbugs/issue18640.go
@@ -11,12 +11,20 @@ type (
b struct {
*a
}
+)
+type (
c struct {
*d
}
d = c
+)
+// The compiler reports an incorrect (non-alias related)
+// type cycle here (via dowith()). Disabled for now.
+// See issue #25838.
+/*
+type (
e = f
f = g
g = []h
@@ -24,3 +32,16 @@ type (
i = j
j = e
)
+*/
+
+type (
+ a1 struct{ *b1 }
+ b1 = c1
+ c1 struct{ *b1 }
+)
+
+type (
+ a2 struct{ b2 }
+ b2 = c2
+ c2 struct{ *b2 }
+)
diff --git a/test/fixedbugs/issue23823.go b/test/fixedbugs/issue23823.go
new file mode 100644
index 0000000000..2f802d0988
--- /dev/null
+++ b/test/fixedbugs/issue23823.go
@@ -0,0 +1,15 @@
+// errorcheck
+
+// Copyright 2018 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 p
+
+type I1 = interface {
+ I2
+}
+
+type I2 interface { // ERROR "invalid recursive type"
+ I1
+}
diff --git a/test/fixedbugs/issue24651a.go b/test/fixedbugs/issue24651a.go
new file mode 100644
index 0000000000..5f63635a2a
--- /dev/null
+++ b/test/fixedbugs/issue24651a.go
@@ -0,0 +1,24 @@
+//errorcheck -0 -race -m -m
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:norace
+func Foo(x int) int { // ERROR "cannot inline Foo: marked go:norace with -race compilation$"
+ return x * (x + 1) * (x + 2)
+}
+
+func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+ return x * (x + 1) * (x + 2)
+}
+
+var x = 5
+
+//go:noinline Provide a clean, constant reason for not inlining main
+func main() { // ERROR "cannot inline main: marked go:noinline$"
+ println("Foo(", x, ")=", Foo(x))
+ println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+}
diff --git a/test/fixedbugs/issue24651b.go b/test/fixedbugs/issue24651b.go
new file mode 100644
index 0000000000..2420f61fa6
--- /dev/null
+++ b/test/fixedbugs/issue24651b.go
@@ -0,0 +1,24 @@
+//errorcheck -0 -m -m
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:norace
+func Foo(x int) int { // ERROR "can inline Foo as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+ return x * (x + 1) * (x + 2)
+}
+
+func Bar(x int) int { // ERROR "can inline Bar as: func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+ return x * (x + 1) * (x + 2)
+}
+
+var x = 5
+
+//go:noinline Provide a clean, constant reason for not inlining main
+func main() { // ERROR "cannot inline main: marked go:noinline$"
+ println("Foo(", x, ")=", Foo(x)) // ERROR "inlining call to Foo func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+ println("Bar(", x, ")=", Bar(x)) // ERROR "inlining call to Bar func\(int\) int { return x \* \(x \+ 1\) \* \(x \+ 2\) }$"
+}
diff --git a/test/fixedbugs/issue24763.go b/test/fixedbugs/issue24763.go
new file mode 100644
index 0000000000..623ab489e8
--- /dev/null
+++ b/test/fixedbugs/issue24763.go
@@ -0,0 +1,21 @@
+// run
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+func main() {
+ var s uint
+ var x = interface{}(1<<s + 1<<s) // compiler must not crash here
+ if x.(int) != 2 {
+ panic("x not int or not 2")
+ }
+
+ var y interface{}
+ y = 1<<s + 1 // compiler must not crash here
+ if y.(int) != 2 {
+ panic("y not int or not 2")
+ }
+}
diff --git a/test/fixedbugs/issue24939.go b/test/fixedbugs/issue24939.go
new file mode 100644
index 0000000000..26530e95b2
--- /dev/null
+++ b/test/fixedbugs/issue24939.go
@@ -0,0 +1,21 @@
+// compile
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+type T interface {
+ M(P)
+}
+
+type M interface {
+ F() P
+}
+
+type P = interface {
+ I() M
+}
+
+func main() {}
diff --git a/test/fixedbugs/issue25727.go b/test/fixedbugs/issue25727.go
new file mode 100644
index 0000000000..9b7c804a0e
--- /dev/null
+++ b/test/fixedbugs/issue25727.go
@@ -0,0 +1,21 @@
+// errorcheck
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "net/http"
+
+var s = http.Server{}
+var _ = s.doneChan // ERROR "s.doneChan undefined .cannot refer to unexported field or method doneChan.$"
+var _ = s.DoneChan // ERROR "s.DoneChan undefined .type http.Server has no field or method DoneChan.$"
+var _ = http.Server{tlsConfig: nil} // ERROR "unknown field 'tlsConfig' in struct literal.+ .but does have TLSConfig.$"
+var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$"
+
+type foo struct {
+ bar int
+}
+
+var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$"
diff --git a/test/fixedbugs/issue25776.go b/test/fixedbugs/issue25776.go
new file mode 100644
index 0000000000..e05c0bce4d
--- /dev/null
+++ b/test/fixedbugs/issue25776.go
@@ -0,0 +1,99 @@
+// run
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+const (
+ Upper = true
+ blas_Upper = 121
+ badTriangle = "bad triangle"
+)
+
+// Triangular represents a triangular matrix. Triangular matrices are always square.
+type Triangular interface {
+ // Triangular returns the number of rows/columns in the matrix and its
+ // orientation.
+ Tryangle() (mmmm int, kynd bool)
+ Triangle() (mmmm int, kynd bool)
+}
+
+// blas64_Triangular represents a triangular matrix using the conventional storage scheme.
+type blas64_Triangular struct {
+ Stride int
+ Uplo int
+}
+
+// TriDense represents an upper or lower triangular matrix in dense storage
+// format.
+type TriDense struct {
+ mat blas64_Triangular
+}
+
+func NewTriDense() *TriDense {
+ return &TriDense{
+ mat: blas64_Triangular{
+ Stride: 3,
+ Uplo: blas_Upper,
+ },
+ }
+}
+
+func (t *TriDense) isUpper() bool {
+ return isUpperUplo(t.mat.Uplo)
+}
+
+func (t *TriDense) triKind() bool {
+ return isUpperUplo(t.mat.Uplo)
+}
+
+func isUpperUplo(u int) bool {
+ switch u {
+ case blas_Upper:
+ return true
+ default:
+ panic(badTriangle)
+ }
+}
+
+func (t *TriDense) IsZero() bool {
+ return t.mat.Stride == 0
+}
+
+//go:noinline
+func (t *TriDense) ScaleTri(f float64, a Triangular) {
+ n, kind := a.Triangle()
+ if kind == false {
+ println("ScaleTri n, kind=", n, ", ", kind, " (FAIL, expected true)")
+ }
+}
+
+//go:noinline
+func (t *TriDense) ScaleTry(f float64, a Triangular) {
+ n, kind := a.Tryangle()
+ if kind == false {
+ println("ScaleTry n, kind=", n, ", ", kind, " (FAIL, expected true)")
+ }
+}
+
+// Triangle failed (before fix)
+func (t *TriDense) Triangle() (nnnn int, kind bool) {
+ return 3, !t.IsZero() && t.triKind()
+}
+
+// Tryangle works -- difference is not-named output parameters.
+func (t *TriDense) Tryangle() (int, bool) {
+ return 3, !t.IsZero() && t.triKind()
+}
+
+func main() {
+ ta := NewTriDense()
+ n, kind := ta.Triangle()
+ if kind == false {
+ println(" main n, kind=", n, ", ", kind, " (FAIL, expected true)")
+ }
+ ta.ScaleTri(1, ta)
+ ta.ScaleTry(1, ta)
+}
diff --git a/test/fixedbugs/issue25958.go b/test/fixedbugs/issue25958.go
new file mode 100644
index 0000000000..ba7ee82230
--- /dev/null
+++ b/test/fixedbugs/issue25958.go
@@ -0,0 +1,17 @@
+// errorcheck
+
+// Copyright 2018 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 p
+
+// Verify that the "must be receive" error for "case done:" appears
+// on the line of the case clause, not the line of the done declaration.
+
+func f(done chan struct{}) {
+ select {
+ case done: // ERROR "must be receive", "not used"
+ case (chan struct{})(done): // ERROR "must be receive"
+ }
+}
diff --git a/test/fixedbugs/issue25966.go b/test/fixedbugs/issue25966.go
new file mode 100644
index 0000000000..7b5f2a7e4f
--- /dev/null
+++ b/test/fixedbugs/issue25966.go
@@ -0,0 +1,24 @@
+// compile -N
+
+// Copyright 2018 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 25966: liveness code complains autotmp live on
+// function entry.
+
+package p
+
+var F = []func(){
+ func() func() { return (func())(nil) }(),
+}
+
+var A = []int{}
+
+type ss struct {
+ string
+ float64
+ i int
+}
+
+var V = A[ss{}.i]
diff --git a/test/fixedbugs/issue25984.dir/p.go b/test/fixedbugs/issue25984.dir/p.go
new file mode 100644
index 0000000000..306d6a489f
--- /dev/null
+++ b/test/fixedbugs/issue25984.dir/p.go
@@ -0,0 +1,15 @@
+// Copyright 2018 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 p
+
+type m struct {
+ link *m
+}
+
+var head *m
+
+func F(m *int) bool {
+ return head != nil
+}
diff --git a/test/fixedbugs/issue25984.dir/q.go b/test/fixedbugs/issue25984.dir/q.go
new file mode 100644
index 0000000000..64d25870b7
--- /dev/null
+++ b/test/fixedbugs/issue25984.dir/q.go
@@ -0,0 +1,11 @@
+// Copyright 2018 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 q
+
+import "./p"
+
+func G() {
+ p.F(nil)
+}
diff --git a/test/fixedbugs/issue25984.go b/test/fixedbugs/issue25984.go
new file mode 100644
index 0000000000..128cf9d06a
--- /dev/null
+++ b/test/fixedbugs/issue25984.go
@@ -0,0 +1,7 @@
+// compiledir
+
+// Copyright 2018 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 ignored
diff --git a/test/fixedbugs/issue25993.go b/test/fixedbugs/issue25993.go
new file mode 100644
index 0000000000..3253cd82f8
--- /dev/null
+++ b/test/fixedbugs/issue25993.go
@@ -0,0 +1,21 @@
+// compile -d=ssa/check/on
+
+// Copyright 2018 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 25993: SSA check fails on ARM.
+
+package p
+
+func f() {
+ var x int
+ var B0 bool
+ B0 = !B0 || B0
+ if B0 && B0 {
+ x = -1
+ }
+ var AI []int
+ var AB []bool
+ _ = AI[x] > 0 && AB[x]
+}
diff --git a/test/fixedbugs/issue26043.go b/test/fixedbugs/issue26043.go
new file mode 100644
index 0000000000..fe32947b07
--- /dev/null
+++ b/test/fixedbugs/issue26043.go
@@ -0,0 +1,32 @@
+// compile
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This program results in a loop inferred to increment
+// j by 0, causing bounds check elimination to attempt
+// something%0, which panics (in the bug).
+
+package q
+
+func f() {
+ var s1 string
+ var b bool
+ if b {
+ b = !b
+ s1 += "a"
+ }
+
+ var s2 string
+ var i, j int
+ if (s1 <= "") || (s2 >= "") {
+ j = len(s1[:6])
+ } else {
+ i = len("b")
+ }
+
+ for j < 0 {
+ j += i
+ }
+}
diff --git a/test/fixedbugs/issue26097.go b/test/fixedbugs/issue26097.go
new file mode 100644
index 0000000000..eedd6bacd0
--- /dev/null
+++ b/test/fixedbugs/issue26097.go
@@ -0,0 +1,47 @@
+// run
+
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+//go:noinline
+func cmovClobberAX64(v1, v2 int64, x1, x2 float64) int64 {
+ r := v1
+ if x1 == x2 {
+ r = v2
+ }
+ return r
+}
+
+//go:noinline
+func cmovClobberAX32(v1, v2 int32, x1, x2 float64) int32 {
+ r := v1
+ if x1 == x2 {
+ r = v2
+ }
+ return r
+}
+
+//go:noinline
+func cmovClobberAX16(v1, v2 int16, x1, x2 float64) int16 {
+ r := v1
+ if x1 == x2 {
+ r = v2
+ }
+ return r
+}
+
+func main() {
+ if cmovClobberAX16(1, 2, 4.0, 5.0) != 1 {
+ panic("CMOVQEQF causes incorrect code")
+ }
+ if cmovClobberAX32(1, 2, 4.0, 5.0) != 1 {
+ panic("CMOVQEQF causes incorrect code")
+ }
+ if cmovClobberAX64(1, 2, 4.0, 5.0) != 1 {
+ panic("CMOVQEQF causes incorrect code")
+ }
+
+}
diff --git a/test/fixedbugs/issue26105.go b/test/fixedbugs/issue26105.go
new file mode 100644
index 0000000000..88a5f162f3
--- /dev/null
+++ b/test/fixedbugs/issue26105.go
@@ -0,0 +1,25 @@
+// compile
+
+// Copyright 2018 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.
+
+// Triggers a bug in writebarrier, which inserts one
+// between (first block) OpAddr x and (second block) a VarDef x,
+// which are then in the wrong order and unable to be
+// properly scheduled.
+
+package q
+
+var S interface{}
+
+func F(n int) {
+ fun := func(x int) int {
+ S = 1
+ return n
+ }
+ i := fun(([]int{})[n])
+
+ var fc [2]chan int
+ S = (([1][2]chan int{fc})[i][i])
+}
diff --git a/test/fixedbugs/issue26120.go b/test/fixedbugs/issue26120.go
new file mode 100644
index 0000000000..94bf7d9cb7
--- /dev/null
+++ b/test/fixedbugs/issue26120.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2018 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 26120: INDEX of 1-element but non-SSAable array
+// is mishandled when building SSA.
+
+package p
+
+type T [1]struct {
+ f []int
+ i, j int
+}
+
+func F() {
+ var v T
+ f := func() T {
+ return v
+ }
+ _ = []int{}[f()[0].i]
+}
diff --git a/test/strcopy.go b/test/strcopy.go
new file mode 100644
index 0000000000..6d32baeec5
--- /dev/null
+++ b/test/strcopy.go
@@ -0,0 +1,29 @@
+// run
+
+// Copyright 2018 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.
+
+// Test that string([]byte(string)) makes a copy and doesn't reduce to
+// nothing. (Issue 25834)
+
+package main
+
+import (
+ "reflect"
+ "unsafe"
+)
+
+func main() {
+ var (
+ buf = make([]byte, 2<<10)
+ large = string(buf)
+ sub = large[10:12]
+ subcopy = string([]byte(sub))
+ subh = *(*reflect.StringHeader)(unsafe.Pointer(&sub))
+ subcopyh = *(*reflect.StringHeader)(unsafe.Pointer(&subcopy))
+ )
+ if subh.Data == subcopyh.Data {
+ panic("sub and subcopy have the same underlying array")
+ }
+}