aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDmitri Shuralyov <dmitshur@golang.org>2020-07-08 23:29:54 -0400
committerDmitri Shuralyov <dmitshur@golang.org>2020-07-09 17:52:30 -0400
commita91ad4250c118d97d2f7fad648313fcb09b38d5f (patch)
treef4096744f2c54b1e91eedf785325fcd80b339852
parent5beb39baf87415ceedd28c5bde0a32419fa3b577 (diff)
parent3b6b86d1fe4275c0d5f89019a0170fa203c0d105 (diff)
downloadgo-a91ad4250c118d97d2f7fad648313fcb09b38d5f.tar.gz
go-a91ad4250c118d97d2f7fad648313fcb09b38d5f.zip
[dev.boringcrypto] all: merge master into dev.boringcrypto
Change-Id: I948e086e11e1da571e2be23bb08a7bbd6618dc2f
-rw-r--r--.gitattributes20
-rw-r--r--AUTHORS5
-rw-r--r--CONTRIBUTORS7
-rw-r--r--api/go1.15.txt132
-rw-r--r--api/next.txt3
-rw-r--r--doc/contribute.html144
-rw-r--r--doc/editors.html2
-rw-r--r--doc/effective_go.html12
-rw-r--r--doc/gccgo_install.html25
-rw-r--r--doc/go1.10.html4
-rw-r--r--doc/go1.14.html10
-rw-r--r--doc/go1.15.html705
-rw-r--r--doc/go_faq.html2
-rw-r--r--doc/help.html2
-rw-r--r--doc/install-source.html18
-rw-r--r--misc/cgo/test/test.go4
-rw-r--r--misc/cgo/test/testdata/issue27054/egl.h1
-rw-r--r--misc/cgo/test/testdata/issue27054/test27054.go6
-rw-r--r--misc/cgo/testgodefs/testdata/issue39534.go12
-rw-r--r--misc/cgo/testgodefs/testgodefs_test.go1
-rw-r--r--misc/cgo/testplugin/plugin_test.go2
-rw-r--r--misc/cgo/testshared/shared_test.go22
-rw-r--r--misc/cgo/testshared/testdata/gcdata/main/main.go37
-rw-r--r--misc/cgo/testshared/testdata/gcdata/p/p.go7
-rw-r--r--misc/cgo/testshared/testdata/issue39777/a/a.go9
-rw-r--r--misc/cgo/testshared/testdata/issue39777/b/b.go7
-rw-r--r--misc/wasm/wasm_exec.js48
-rw-r--r--src/all.bat54
-rw-r--r--src/bufio/scan_test.go14
-rw-r--r--src/clean.bat64
-rw-r--r--src/cmd/addr2line/addr2line_test.go16
-rw-r--r--src/cmd/asm/doc.go7
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64.s3
-rw-r--r--src/cmd/asm/internal/asm/testdata/arm64enc.s1
-rw-r--r--src/cmd/cgo/doc.go11
-rw-r--r--src/cmd/cgo/gcc.go10
-rw-r--r--src/cmd/cgo/out.go5
-rw-r--r--src/cmd/compile/doc.go2
-rw-r--r--src/cmd/compile/fmt_test.go15
-rw-r--r--src/cmd/compile/fmtmap_test.go5
-rw-r--r--src/cmd/compile/internal/amd64/ssa.go8
-rw-r--r--src/cmd/compile/internal/arm/ssa.go51
-rw-r--r--src/cmd/compile/internal/arm64/ssa.go69
-rw-r--r--src/cmd/compile/internal/gc/alg.go89
-rw-r--r--src/cmd/compile/internal/gc/builtin.go626
-rw-r--r--src/cmd/compile/internal/gc/builtin/runtime.go2
-rw-r--r--src/cmd/compile/internal/gc/esc.go12
-rw-r--r--src/cmd/compile/internal/gc/fmt.go176
-rw-r--r--src/cmd/compile/internal/gc/gsubr.go2
-rw-r--r--src/cmd/compile/internal/gc/noder.go2
-rw-r--r--src/cmd/compile/internal/gc/op_string.go161
-rw-r--r--src/cmd/compile/internal/gc/order.go76
-rw-r--r--src/cmd/compile/internal/gc/pgen.go25
-rw-r--r--src/cmd/compile/internal/gc/plive.go14
-rw-r--r--src/cmd/compile/internal/gc/reproduciblebuilds_test.go50
-rw-r--r--src/cmd/compile/internal/gc/ssa.go41
-rw-r--r--src/cmd/compile/internal/gc/subr.go8
-rw-r--r--src/cmd/compile/internal/gc/syntax.go60
-rw-r--r--src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go70
-rw-r--r--src/cmd/compile/internal/gc/typecheck.go50
-rw-r--r--src/cmd/compile/internal/gc/walk.go60
-rw-r--r--src/cmd/compile/internal/ssa/check.go5
-rw-r--r--src/cmd/compile/internal/ssa/compile.go3
-rw-r--r--src/cmd/compile/internal/ssa/cse.go38
-rw-r--r--src/cmd/compile/internal/ssa/deadstore.go16
-rw-r--r--src/cmd/compile/internal/ssa/debug_test.go20
-rw-r--r--src/cmd/compile/internal/ssa/flags_amd64_test.s31
-rw-r--r--src/cmd/compile/internal/ssa/flags_arm64_test.s32
-rw-r--r--src/cmd/compile/internal/ssa/flags_test.go108
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM.rules368
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64.rules284
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARM64Ops.go18
-rw-r--r--src/cmd/compile/internal/ssa/gen/ARMOps.go18
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64.rules29
-rw-r--r--src/cmd/compile/internal/ssa/gen/PPC64Ops.go24
-rw-r--r--src/cmd/compile/internal/ssa/gen/RISCV64.rules32
-rw-r--r--src/cmd/compile/internal/ssa/gen/S390XOps.go37
-rw-r--r--src/cmd/compile/internal/ssa/gen/rulegen.go4
-rw-r--r--src/cmd/compile/internal/ssa/op.go1
-rw-r--r--src/cmd/compile/internal/ssa/opGen.go254
-rw-r--r--src/cmd/compile/internal/ssa/prove.go33
-rw-r--r--src/cmd/compile/internal/ssa/rewrite.go255
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM.go1701
-rw-r--r--src/cmd/compile/internal/ssa/rewriteARM64.go1552
-rw-r--r--src/cmd/compile/internal/ssa/rewriteCond_test.go597
-rw-r--r--src/cmd/compile/internal/ssa/rewritePPC64.go76
-rw-r--r--src/cmd/compile/internal/ssa/rewriteRISCV64.go125
-rw-r--r--src/cmd/compile/internal/ssa/rewrite_test.go9
-rw-r--r--src/cmd/compile/internal/ssa/tuple.go59
-rw-r--r--src/cmd/compile/internal/ssa/value.go2
-rw-r--r--src/cmd/compile/internal/x86/ssa.go8
-rw-r--r--src/cmd/dist/build.go11
-rw-r--r--src/cmd/dist/buildruntime.go2
-rw-r--r--src/cmd/dist/buildtool.go1
-rw-r--r--src/cmd/dist/test.go21
-rw-r--r--src/cmd/fix/egltype.go28
-rw-r--r--src/cmd/fix/egltype_test.go141
-rw-r--r--src/cmd/go.mod8
-rw-r--r--src/cmd/go.sum16
-rw-r--r--src/cmd/go/alldocs.go114
-rw-r--r--src/cmd/go/go_test.go39
-rw-r--r--src/cmd/go/internal/cfg/cfg.go3
-rw-r--r--src/cmd/go/internal/clean/clean.go25
-rw-r--r--src/cmd/go/internal/help/helpdoc.go106
-rw-r--r--src/cmd/go/internal/load/pkg.go83
-rw-r--r--src/cmd/go/internal/load/test.go2
-rw-r--r--src/cmd/go/internal/modfetch/proxy.go20
-rw-r--r--src/cmd/go/internal/modget/get.go12
-rw-r--r--src/cmd/go/internal/modload/import.go104
-rw-r--r--src/cmd/go/internal/modload/load.go38
-rw-r--r--src/cmd/go/internal/modload/mvs.go6
-rw-r--r--src/cmd/go/internal/modload/query.go51
-rw-r--r--src/cmd/go/internal/modload/search.go44
-rw-r--r--src/cmd/go/internal/mvs/mvs.go23
-rw-r--r--src/cmd/go/internal/search/search.go12
-rw-r--r--src/cmd/go/internal/test/test.go14
-rw-r--r--src/cmd/go/internal/test/testflag.go17
-rw-r--r--src/cmd/go/internal/web/http.go8
-rw-r--r--src/cmd/go/internal/work/exec.go14
-rw-r--r--src/cmd/go/internal/work/gc.go2
-rw-r--r--src/cmd/go/internal/work/security.go3
-rw-r--r--src/cmd/go/internal/work/security_test.go2
-rw-r--r--src/cmd/go/note_test.go2
-rw-r--r--src/cmd/go/proxy_test.go19
-rw-r--r--src/cmd/go/script_test.go284
-rw-r--r--src/cmd/go/testdata/script/README6
-rw-r--r--src/cmd/go/testdata/script/build_trimpath.txt4
-rw-r--r--src/cmd/go/testdata/script/clean_cache_n.txt25
-rw-r--r--src/cmd/go/testdata/script/generate_env.txt3
-rw-r--r--src/cmd/go/testdata/script/goroot_executable.txt7
-rw-r--r--src/cmd/go/testdata/script/issue36000.txt6
-rw-r--r--src/cmd/go/testdata/script/list_case_collision.txt10
-rw-r--r--src/cmd/go/testdata/script/list_dedup_packages.txt2
-rw-r--r--src/cmd/go/testdata/script/list_gofile_in_goroot.txt3
-rw-r--r--src/cmd/go/testdata/script/list_permissions.txt84
-rw-r--r--src/cmd/go/testdata/script/mod_convert_dep.txt1
-rw-r--r--src/cmd/go/testdata/script/mod_get_too_many_redirects.txt10
-rw-r--r--src/cmd/go/testdata/script/mod_gomodcache.txt3
-rw-r--r--src/cmd/go/testdata/script/mod_gonoproxy.txt15
-rw-r--r--src/cmd/go/testdata/script/script_wait.txt7
-rw-r--r--src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt32
-rw-r--r--src/cmd/go/testdata/script/test_benchmark_chatty_success.txt29
-rw-r--r--src/cmd/go/testdata/script/test_chatty_fail.txt32
-rw-r--r--src/cmd/go/testdata/script/test_chatty_parallel_fail.txt58
-rw-r--r--src/cmd/go/testdata/script/test_chatty_parallel_success.txt52
-rw-r--r--src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt39
-rw-r--r--src/cmd/go/testdata/script/test_chatty_success.txt27
-rw-r--r--src/cmd/go/testdata/script/test_flags.txt14
-rw-r--r--src/cmd/go/testdata/script/test_regexps.txt14
-rw-r--r--src/cmd/internal/goobj/goobj_test.go19
-rw-r--r--src/cmd/internal/goobj/readnew.go19
-rw-r--r--src/cmd/internal/goobj2/objfile.go53
-rw-r--r--src/cmd/internal/moddeps/moddeps_test.go2
-rw-r--r--src/cmd/internal/obj/arm/a.out.go2
-rw-r--r--src/cmd/internal/obj/arm/asm5.go2
-rw-r--r--src/cmd/internal/obj/arm/list5.go2
-rw-r--r--src/cmd/internal/obj/arm/obj5.go2
-rw-r--r--src/cmd/internal/obj/arm64/asm7.go14
-rw-r--r--src/cmd/internal/obj/arm64/doc.go5
-rw-r--r--src/cmd/internal/obj/arm64/obj7.go9
-rw-r--r--src/cmd/internal/obj/data.go4
-rw-r--r--src/cmd/internal/obj/ld.go4
-rw-r--r--src/cmd/internal/obj/link.go2
-rw-r--r--src/cmd/internal/obj/objfile.go8
-rw-r--r--src/cmd/internal/obj/objfile2.go39
-rw-r--r--src/cmd/internal/obj/pass.go2
-rw-r--r--src/cmd/internal/obj/ppc64/doc.go52
-rw-r--r--src/cmd/internal/obj/sym.go4
-rw-r--r--src/cmd/internal/obj/x86/a.out.go2
-rw-r--r--src/cmd/internal/obj/x86/asm6.go2
-rw-r--r--src/cmd/internal/obj/x86/list6.go2
-rw-r--r--src/cmd/internal/obj/x86/obj6.go2
-rw-r--r--src/cmd/internal/objabi/autotype.go2
-rw-r--r--src/cmd/internal/objabi/head.go2
-rw-r--r--src/cmd/internal/objabi/reloctype.go2
-rw-r--r--src/cmd/internal/objabi/symkind.go2
-rw-r--r--src/cmd/internal/objabi/util.go13
-rw-r--r--src/cmd/internal/test2json/test2json.go12
-rw-r--r--src/cmd/internal/test2json/testdata/issue29755.json38
-rw-r--r--src/cmd/internal/test2json/testdata/issue29755.test27
-rw-r--r--src/cmd/internal/test2json/testdata/smiley.json22
-rw-r--r--src/cmd/internal/test2json/testdata/smiley.test22
-rw-r--r--src/cmd/internal/test2json/testdata/vet.json22
-rw-r--r--src/cmd/internal/test2json/testdata/vet.test22
-rw-r--r--src/cmd/link/dwarf_test.go4
-rw-r--r--src/cmd/link/internal/amd64/asm.go2
-rw-r--r--src/cmd/link/internal/amd64/l.go2
-rw-r--r--src/cmd/link/internal/amd64/obj.go2
-rw-r--r--src/cmd/link/internal/arm/asm.go8
-rw-r--r--src/cmd/link/internal/arm/l.go4
-rw-r--r--src/cmd/link/internal/arm/obj.go2
-rw-r--r--src/cmd/link/internal/arm64/asm.go2
-rw-r--r--src/cmd/link/internal/arm64/l.go2
-rw-r--r--src/cmd/link/internal/arm64/obj.go2
-rw-r--r--src/cmd/link/internal/ld/ar.go2
-rw-r--r--src/cmd/link/internal/ld/data.go8
-rw-r--r--src/cmd/link/internal/ld/decodesym.go27
-rw-r--r--src/cmd/link/internal/ld/dwarf.go12
-rw-r--r--src/cmd/link/internal/ld/dwarf_test.go111
-rw-r--r--src/cmd/link/internal/ld/fallocate_test.go65
-rw-r--r--src/cmd/link/internal/ld/ld.go11
-rw-r--r--src/cmd/link/internal/ld/lib.go33
-rw-r--r--src/cmd/link/internal/ld/link.go2
-rw-r--r--src/cmd/link/internal/ld/macho.go4
-rw-r--r--src/cmd/link/internal/ld/main.go2
-rw-r--r--src/cmd/link/internal/ld/outbuf.go1
-rw-r--r--src/cmd/link/internal/ld/outbuf_darwin.go20
-rw-r--r--src/cmd/link/internal/ld/outbuf_linux.go2
-rw-r--r--src/cmd/link/internal/ld/outbuf_mmap.go8
-rw-r--r--src/cmd/link/internal/ld/outbuf_windows.go8
-rw-r--r--src/cmd/link/internal/ld/pcln.go2
-rw-r--r--src/cmd/link/internal/ld/pe.go13
-rw-r--r--src/cmd/link/internal/ld/sym.go4
-rw-r--r--src/cmd/link/internal/ld/symtab.go2
-rw-r--r--src/cmd/link/internal/ld/testdata/issue38192/main.go11
-rw-r--r--src/cmd/link/internal/ld/testdata/issue38192/oneline.s8
-rw-r--r--src/cmd/link/internal/loader/loader.go22
-rw-r--r--src/cmd/link/internal/mips/asm.go2
-rw-r--r--src/cmd/link/internal/mips/l.go2
-rw-r--r--src/cmd/link/internal/mips/obj.go2
-rw-r--r--src/cmd/link/internal/mips64/asm.go2
-rw-r--r--src/cmd/link/internal/mips64/l.go2
-rw-r--r--src/cmd/link/internal/mips64/obj.go2
-rw-r--r--src/cmd/link/internal/ppc64/asm.go17
-rw-r--r--src/cmd/link/internal/ppc64/l.go2
-rw-r--r--src/cmd/link/internal/ppc64/obj.go2
-rw-r--r--src/cmd/link/internal/s390x/asm.go2
-rw-r--r--src/cmd/link/internal/s390x/l.go2
-rw-r--r--src/cmd/link/internal/s390x/obj.go2
-rw-r--r--src/cmd/link/internal/sym/segment.go2
-rw-r--r--src/cmd/link/internal/sym/symbols.go2
-rw-r--r--src/cmd/link/internal/sym/symkind.go2
-rw-r--r--src/cmd/link/internal/x86/asm.go2
-rw-r--r--src/cmd/link/internal/x86/l.go2
-rw-r--r--src/cmd/link/internal/x86/obj.go2
-rw-r--r--src/cmd/link/link_test.go53
-rw-r--r--src/cmd/link/testdata/testPErsrc/main.go19
-rw-r--r--src/cmd/link/testdata/testPErsrc/rsrc.sysobin0 -> 228 bytes
-rw-r--r--src/cmd/nm/nm_test.go10
-rw-r--r--src/cmd/objdump/objdump_test.go18
-rw-r--r--src/cmd/oldlink/internal/amd64/asm.go2
-rw-r--r--src/cmd/oldlink/internal/amd64/l.go2
-rw-r--r--src/cmd/oldlink/internal/amd64/obj.go2
-rw-r--r--src/cmd/oldlink/internal/arm/asm.go8
-rw-r--r--src/cmd/oldlink/internal/arm/l.go4
-rw-r--r--src/cmd/oldlink/internal/arm/obj.go2
-rw-r--r--src/cmd/oldlink/internal/arm64/asm.go2
-rw-r--r--src/cmd/oldlink/internal/arm64/l.go2
-rw-r--r--src/cmd/oldlink/internal/arm64/obj.go2
-rw-r--r--src/cmd/oldlink/internal/ld/ar.go2
-rw-r--r--src/cmd/oldlink/internal/ld/data.go4
-rw-r--r--src/cmd/oldlink/internal/ld/decodesym.go32
-rw-r--r--src/cmd/oldlink/internal/ld/ld.go4
-rw-r--r--src/cmd/oldlink/internal/ld/lib.go8
-rw-r--r--src/cmd/oldlink/internal/ld/link.go2
-rw-r--r--src/cmd/oldlink/internal/ld/main.go2
-rw-r--r--src/cmd/oldlink/internal/ld/pcln.go2
-rw-r--r--src/cmd/oldlink/internal/ld/sym.go4
-rw-r--r--src/cmd/oldlink/internal/ld/symtab.go2
-rw-r--r--src/cmd/oldlink/internal/mips/asm.go2
-rw-r--r--src/cmd/oldlink/internal/mips/l.go2
-rw-r--r--src/cmd/oldlink/internal/mips/obj.go2
-rw-r--r--src/cmd/oldlink/internal/mips64/asm.go2
-rw-r--r--src/cmd/oldlink/internal/mips64/l.go2
-rw-r--r--src/cmd/oldlink/internal/mips64/obj.go2
-rw-r--r--src/cmd/oldlink/internal/objfile/objfile.go6
-rw-r--r--src/cmd/oldlink/internal/ppc64/asm.go8
-rw-r--r--src/cmd/oldlink/internal/ppc64/l.go2
-rw-r--r--src/cmd/oldlink/internal/ppc64/obj.go2
-rw-r--r--src/cmd/oldlink/internal/s390x/asm.go2
-rw-r--r--src/cmd/oldlink/internal/s390x/l.go2
-rw-r--r--src/cmd/oldlink/internal/s390x/obj.go2
-rw-r--r--src/cmd/oldlink/internal/sym/attribute.go6
-rw-r--r--src/cmd/oldlink/internal/sym/segment.go2
-rw-r--r--src/cmd/oldlink/internal/sym/symbols.go2
-rw-r--r--src/cmd/oldlink/internal/sym/symkind.go2
-rw-r--r--src/cmd/oldlink/internal/x86/asm.go2
-rw-r--r--src/cmd/oldlink/internal/x86/l.go2
-rw-r--r--src/cmd/oldlink/internal/x86/obj.go2
-rw-r--r--src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go15
-rw-r--r--src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go165
-rw-r--r--src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go105
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go9
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go1
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go2
-rw-r--r--src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go5
-rw-r--r--src/cmd/vendor/modules.txt8
-rw-r--r--src/container/list/list.go4
-rw-r--r--src/crypto/elliptic/elliptic.go70
-rw-r--r--src/crypto/elliptic/elliptic_test.go147
-rw-r--r--src/crypto/hmac/hmac.go80
-rw-r--r--src/crypto/hmac/hmac_test.go13
-rw-r--r--src/crypto/tls/common.go298
-rw-r--r--src/crypto/tls/conn.go48
-rw-r--r--src/crypto/tls/example_test.go79
-rw-r--r--src/crypto/tls/generate_cert.go12
-rw-r--r--src/crypto/tls/handshake_client.go82
-rw-r--r--src/crypto/tls/handshake_client_test.go488
-rw-r--r--src/crypto/tls/handshake_client_tls13.go13
-rw-r--r--src/crypto/tls/handshake_messages_test.go1
-rw-r--r--src/crypto/tls/handshake_server.go85
-rw-r--r--src/crypto/tls/handshake_server_test.go14
-rw-r--r--src/crypto/tls/handshake_server_tls13.go17
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial83
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN83
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch83
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial81
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-IssueTicket167
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable167
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-Resume82
-rw-r--r--src/crypto/tls/ticket.go30
-rw-r--r--src/crypto/tls/tls.go2
-rw-r--r--src/crypto/tls/tls_test.go28
-rw-r--r--src/crypto/x509/cert_pool.go12
-rw-r--r--src/crypto/x509/internal/macOS/corefoundation.go141
-rw-r--r--src/crypto/x509/internal/macOS/corefoundation.s26
-rw-r--r--src/crypto/x509/internal/macOS/security.go116
-rw-r--r--src/crypto/x509/internal/macOS/security.s16
-rw-r--r--src/crypto/x509/root.go2
-rw-r--r--src/crypto/x509/root_cgo_darwin_amd64.go (renamed from src/crypto/x509/root_cgo_darwin.go)12
-rw-r--r--src/crypto/x509/root_darwin.go288
-rw-r--r--src/crypto/x509/root_darwin_amd64.go243
-rw-r--r--src/crypto/x509/root_darwin_arm_gen.go184
-rw-r--r--src/crypto/x509/root_darwin_ios.go (renamed from src/crypto/x509/root_darwin_arm64.go)2121
-rw-r--r--src/crypto/x509/root_darwin_ios_gen.go179
-rw-r--r--src/crypto/x509/root_darwin_test.go98
-rw-r--r--src/crypto/x509/root_nocgo_darwin.go11
-rw-r--r--src/crypto/x509/root_omit.go10
-rw-r--r--src/crypto/x509/root_omit_test.go3
-rw-r--r--src/crypto/x509/root_unix_test.go5
-rw-r--r--src/crypto/x509/verify.go98
-rw-r--r--src/crypto/x509/verify_test.go43
-rw-r--r--src/crypto/x509/x509.go22
-rw-r--r--src/crypto/x509/x509_test.go132
-rw-r--r--src/database/sql/driver/driver.go2
-rw-r--r--src/database/sql/sql.go5
-rw-r--r--src/encoding/asn1/asn1.go12
-rw-r--r--src/encoding/asn1/asn1_test.go12
-rw-r--r--src/encoding/asn1/marshal.go56
-rw-r--r--src/encoding/asn1/marshal_test.go57
-rw-r--r--src/encoding/json/decode.go69
-rw-r--r--src/encoding/json/decode_test.go49
-rw-r--r--src/encoding/json/encode.go11
-rw-r--r--src/encoding/json/encode_test.go87
-rw-r--r--src/encoding/json/stream_test.go8
-rw-r--r--src/encoding/xml/marshal.go23
-rw-r--r--src/encoding/xml/marshal_test.go41
-rw-r--r--src/encoding/xml/read.go16
-rw-r--r--src/encoding/xml/typeinfo.go16
-rw-r--r--src/go.mod4
-rw-r--r--src/go.sum8
-rw-r--r--src/go/build/build.go3
-rw-r--r--src/go/build/build_test.go9
-rw-r--r--src/go/build/deps_test.go1137
-rw-r--r--src/go/build/doc.go98
-rw-r--r--src/go/internal/srcimporter/srcimporter.go6
-rw-r--r--src/go/internal/srcimporter/srcimporter_test.go10
-rw-r--r--src/go/token/position.go23
-rw-r--r--src/go/types/api.go10
-rw-r--r--src/go/types/check.go4
-rw-r--r--src/go/types/resolver.go4
-rw-r--r--src/html/template/html.go3
-rw-r--r--src/image/gif/writer_test.go7
-rw-r--r--src/image/png/reader.go5
-rw-r--r--src/internal/cfg/cfg.go1
-rw-r--r--src/internal/poll/copy_file_range_linux.go8
-rw-r--r--src/internal/poll/fd_plan9.go29
-rw-r--r--src/internal/poll/fd_unix.go61
-rw-r--r--src/internal/poll/fd_writev_unix.go13
-rw-r--r--src/internal/poll/sendfile_bsd.go3
-rw-r--r--src/internal/poll/sendfile_linux.go3
-rw-r--r--src/internal/poll/splice_linux.go3
-rw-r--r--src/internal/poll/writev.go5
-rw-r--r--src/internal/trace/writer.go4
-rw-r--r--src/io/ioutil/ioutil.go2
-rw-r--r--src/make.bat305
-rw-r--r--src/math/big/link_test.go7
-rw-r--r--src/math/exp_amd64.s2
-rw-r--r--src/net/http/cgi/host.go7
-rw-r--r--src/net/http/fs.go13
-rw-r--r--src/net/http/fs_test.go9
-rw-r--r--src/net/http/httptest/recorder.go4
-rw-r--r--src/net/http/httptest/recorder_test.go36
-rw-r--r--src/net/http/pprof/pprof.go10
-rw-r--r--src/net/http/request.go4
-rw-r--r--src/net/http/server.go6
-rw-r--r--src/net/http/transfer.go16
-rw-r--r--src/net/http/transfer_test.go36
-rw-r--r--src/net/http/transport.go66
-rw-r--r--src/net/http/transport_test.go51
-rw-r--r--src/net/interface_plan9.go4
-rw-r--r--src/net/ipsock_plan9.go32
-rw-r--r--src/net/net.go34
-rw-r--r--src/net/rpc/client.go2
-rw-r--r--src/net/sockopt_aix.go7
-rw-r--r--src/net/sockopt_bsd.go7
-rw-r--r--src/net/sockopt_linux.go7
-rw-r--r--src/net/sockopt_solaris.go7
-rw-r--r--src/net/sockopt_windows.go6
-rw-r--r--src/os/exec_unix.go15
-rw-r--r--src/os/file.go2
-rw-r--r--src/os/file_plan9.go4
-rw-r--r--src/os/file_unix.go6
-rw-r--r--src/os/file_windows.go14
-rw-r--r--src/os/os_test.go31
-rw-r--r--src/os/os_windows_test.go119
-rw-r--r--src/os/readfrom_linux_test.go5
-rw-r--r--src/os/removeall_at.go3
-rw-r--r--src/os/signal/internal/pty/pty.go8
-rw-r--r--src/os/signal/signal_cgo_test.go44
-rw-r--r--src/os/wait_wait6.go23
-rw-r--r--src/os/wait_waitid.go8
-rw-r--r--src/path/filepath/match.go6
-rw-r--r--src/race.bat102
-rw-r--r--src/reflect/all_test.go6
-rw-r--r--src/reflect/deepequal.go16
-rw-r--r--src/reflect/type.go1
-rw-r--r--src/reflect/value.go8
-rw-r--r--src/regexp/syntax/compile.go68
-rw-r--r--src/run.bat113
-rw-r--r--src/runtime/cgo/gcc_android.c2
-rw-r--r--src/runtime/cgo_sigaction.go10
-rw-r--r--src/runtime/crash_cgo_test.go27
-rw-r--r--src/runtime/crash_test.go14
-rw-r--r--src/runtime/debugcall.go2
-rw-r--r--src/runtime/env_plan9.go136
-rw-r--r--src/runtime/env_posix.go2
-rw-r--r--src/runtime/env_test.go4
-rw-r--r--src/runtime/export_test.go25
-rw-r--r--src/runtime/extern.go9
-rw-r--r--src/runtime/gc_test.go10
-rw-r--r--src/runtime/hash_test.go8
-rw-r--r--src/runtime/lock_futex.go6
-rw-r--r--src/runtime/lock_js.go13
-rw-r--r--src/runtime/lock_sema.go6
-rw-r--r--src/runtime/lockrank.go60
-rw-r--r--src/runtime/lockrank_off.go12
-rw-r--r--src/runtime/lockrank_on.go104
-rw-r--r--src/runtime/malloc.go33
-rw-r--r--src/runtime/memclr_arm.s2
-rw-r--r--src/runtime/memmove_386.s2
-rw-r--r--src/runtime/memmove_amd64.s2
-rw-r--r--src/runtime/memmove_arm.s2
-rw-r--r--src/runtime/memmove_plan9_386.s2
-rw-r--r--src/runtime/memmove_plan9_amd64.s2
-rw-r--r--src/runtime/mgcmark.go14
-rw-r--r--src/runtime/mgcscavenge.go343
-rw-r--r--src/runtime/mgcscavenge_test.go6
-rw-r--r--src/runtime/mgcsweep.go78
-rw-r--r--src/runtime/mheap.go48
-rw-r--r--src/runtime/mpagealloc.go181
-rw-r--r--src/runtime/mpagealloc_64bit.go12
-rw-r--r--src/runtime/mpagecache.go12
-rw-r--r--src/runtime/mranges.go186
-rw-r--r--src/runtime/mstats.go2
-rw-r--r--src/runtime/mwbbuf.go7
-rw-r--r--src/runtime/netpoll_stub.go3
-rw-r--r--src/runtime/os_plan9.go7
-rw-r--r--src/runtime/proc.go65
-rw-r--r--src/runtime/proc_test.go24
-rw-r--r--src/runtime/rt0_openbsd_arm64.s8
-rw-r--r--src/runtime/runtime-gdb.py18
-rw-r--r--src/runtime/runtime-gdb_test.go105
-rw-r--r--src/runtime/runtime2.go28
-rw-r--r--src/runtime/signal_unix.go6
-rw-r--r--src/runtime/sizeof_test.go3
-rw-r--r--src/runtime/slice.go49
-rw-r--r--src/runtime/slice_test.go78
-rw-r--r--src/runtime/stack.go23
-rw-r--r--src/runtime/stubs.go2
-rw-r--r--src/runtime/symtab.go4
-rw-r--r--src/runtime/sys_darwin.go17
-rw-r--r--src/runtime/sys_darwin_amd64.s26
-rw-r--r--src/runtime/sys_openbsd_arm.s80
-rw-r--r--src/runtime/sys_openbsd_arm64.s75
-rw-r--r--src/runtime/testdata/testprog/gc.go36
-rw-r--r--src/runtime/testdata/testprog/lockosthread.go49
-rw-r--r--src/runtime/testdata/testprog/numcpu_freebsd.go8
-rw-r--r--src/runtime/testdata/testprogcgo/eintr.go246
-rw-r--r--src/runtime/trace.go12
-rw-r--r--src/runtime/trace/trace.go2
-rw-r--r--src/runtime/trace/trace_stack_test.go1
-rw-r--r--src/runtime/vlop_386.s2
-rw-r--r--src/runtime/vlop_arm.s2
-rw-r--r--src/runtime/vlrt.go2
-rw-r--r--src/strconv/atoc.go105
-rw-r--r--src/strconv/atoc_test.go202
-rw-r--r--src/strconv/atof.go6
-rw-r--r--src/strconv/atof_test.go2
-rw-r--r--src/strconv/atoi.go2
-rw-r--r--src/strconv/ctoa.go27
-rw-r--r--src/syscall/asm_openbsd_arm.s17
-rw-r--r--src/syscall/asm_openbsd_arm64.s16
-rw-r--r--src/syscall/dll_windows.go11
-rw-r--r--src/syscall/env_plan9.go122
-rw-r--r--src/syscall/env_unix.go16
-rw-r--r--src/syscall/exec_linux_test.go6
-rw-r--r--src/syscall/exec_unix.go7
-rw-r--r--src/syscall/js/func.go3
-rw-r--r--src/syscall/js/js_test.go11
-rw-r--r--src/syscall/syscall_dup2_linux.go10
-rw-r--r--src/syscall/syscall_dup3_linux.go9
-rw-r--r--src/syscall/syscall_linux.go16
-rw-r--r--src/syscall/syscall_linux_386.go5
-rw-r--r--src/syscall/syscall_linux_amd64.go5
-rw-r--r--src/syscall/syscall_linux_arm.go5
-rw-r--r--src/syscall/syscall_linux_arm64.go5
-rw-r--r--src/syscall/syscall_linux_mips64x.go5
-rw-r--r--src/syscall/syscall_linux_mipsx.go5
-rw-r--r--src/syscall/syscall_linux_ppc64x.go5
-rw-r--r--src/syscall/syscall_linux_riscv64.go5
-rw-r--r--src/syscall/syscall_linux_s390x.go5
-rw-r--r--src/syscall/syscall_linux_test.go9
-rw-r--r--src/syscall/syscall_windows.go20
-rw-r--r--src/testing/benchmark.go3
-rw-r--r--src/testing/sub_test.go126
-rw-r--r--src/testing/testing.go104
-rw-r--r--src/testing/testing_test.go8
-rw-r--r--src/text/template/link_test.go2
-rw-r--r--src/text/template/parse/node.go2
-rw-r--r--src/time/example_test.go9
-rw-r--r--src/time/format.go2
-rw-r--r--src/vendor/golang.org/x/crypto/cryptobyte/asn1.go4
-rw-r--r--src/vendor/golang.org/x/net/dns/dnsmessage/message.go3
-rw-r--r--src/vendor/modules.txt4
-rw-r--r--test/codegen/arithmetic.go11
-rw-r--r--test/codegen/comparisons.go159
-rw-r--r--test/codegen/slices.go183
-rw-r--r--test/fixedbugs/issue25727.go8
-rw-r--r--test/fixedbugs/issue31053.dir/f1.go18
-rw-r--r--test/fixedbugs/issue31053.dir/main.go42
-rw-r--r--test/fixedbugs/issue31053.go7
-rw-r--r--test/fixedbugs/issue36437.go49
-rw-r--r--test/fixedbugs/issue37246.go23
-rw-r--r--test/fixedbugs/issue38093.go49
-rw-r--r--test/fixedbugs/issue38916.go14
-rw-r--r--test/fixedbugs/issue39459.go22
-rw-r--r--test/fixedbugs/issue39472.go12
-rw-r--r--test/fixedbugs/issue39541.go33
-rw-r--r--test/fixedbugs/issue39651.go26
-rw-r--r--test/fixedbugs/issue8606.go93
-rw-r--r--test/makeslice.go149
-rw-r--r--test/prove.go64
-rw-r--r--test/winbatch.go54
544 files changed, 16929 insertions, 8659 deletions
diff --git a/.gitattributes b/.gitattributes
index bcea0290f4..cabbb1732c 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -1,16 +1,16 @@
# Treat all files in the Go repo as binary, with no git magic updating
-# line endings. Windows users contributing to Go will need to use a
-# modern version of git and editors capable of LF line endings.
+# line endings. This produces predictable results in different environments.
+#
+# Windows users contributing to Go will need to use a modern version
+# of git and editors capable of LF line endings.
+#
+# Windows .bat files are known to have multiple bugs when run with LF
+# endings, and so they are checked in with CRLF endings, with a test
+# in test/winbatch.go to catch problems. (See golang.org/issue/37791.)
#
# We'll prevent accidental CRLF line endings from entering the repo
-# via the git-review gofmt checks.
+# via the git-codereview gofmt checks and tests.
#
-# See golang.org/issue/9281
+# See golang.org/issue/9281.
* -text
-
-# The only exception is Windows files that must absolutely be CRLF or
-# might not work. Batch files are known to have multiple bugs when run
-# with LF endings. See golang.org/issue/37791 for more information.
-
-*.bat text eol=crlf
diff --git a/AUTHORS b/AUTHORS
index d79d4ed7d8..909013052e 100644
--- a/AUTHORS
+++ b/AUTHORS
@@ -934,7 +934,7 @@ Maya Rashish <maya@netbsd.org>
Mayank Kumar <krmayankk@gmail.com>
MediaMath, Inc
Meir Fischer <meirfischer@gmail.com>
-Meng Zhuo <mengzhuo1203@gmail.com>
+Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
Meteor Development Group
Mhd Sulhan <m.shulhan@gmail.com>
Micah Stetson <micah.stetson@gmail.com>
@@ -1044,6 +1044,7 @@ Niels Widger <niels.widger@gmail.com>
Nigel Kerr <nigel.kerr@gmail.com>
Nik Nyby <nnyby@columbia.edu>
Nikhil Benesch <nikhil.benesch@gmail.com>
+Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
Niklas Schnelle <niklas.schnelle@gmail.com>
Niko Dziemba <niko@dziemba.com>
Nikolay Turpitko <nikolay@turpitko.com>
@@ -1142,6 +1143,7 @@ Pietro Gagliardi <pietro10@mac.com>
Piyush Mishra <piyush@codeitout.com>
Platform.sh
Pontus Leitzler <leitzler@gmail.com>
+Prasanga Siripala <pj@pjebs.com.au>
Prashant Varanasi <prashant@prashantv.com>
Pravendra Singh <hackpravj@gmail.com>
Preetam Jinka <pj@preet.am>
@@ -1396,6 +1398,7 @@ Upthere, Inc.
Uriel Mangado <uriel@berlinblue.org>
Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
+Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
Vendasta
Veselkov Konstantin <kostozyb@gmail.com>
Victor Vrantchan <vrancean+github@gmail.com>
diff --git a/CONTRIBUTORS b/CONTRIBUTORS
index ed9784ca11..dec3246176 100644
--- a/CONTRIBUTORS
+++ b/CONTRIBUTORS
@@ -958,7 +958,7 @@ Irfan Sharif <irfanmahmoudsharif@gmail.com>
Irieda Noboru <irieda@gmail.com>
Isaac Ardis <isaac.ardis@gmail.com>
Isaac Wagner <ibw@isaacwagner.me>
-Isfan Azhabil <isfan.azhabil@tokopedia.com>
+Isfan Azhabil <isfanazhabil@gmail.com>
Iskander Sharipov <iskander.sharipov@intel.com> <quasilyte@gmail.com>
Issac Trotts <issactrotts@google.com>
Ivan Babrou <ivan@cloudflare.com>
@@ -1501,7 +1501,7 @@ Maxwell Krohn <themax@gmail.com>
Maya Rashish <maya@NetBSD.org>
Mayank Kumar <krmayankk@gmail.com>
Meir Fischer <meirfischer@gmail.com>
-Meng Zhuo <mengzhuo1203@gmail.com>
+Meng Zhuo <mengzhuo1203@gmail.com> <mzh@golangcn.org>
Mhd Sulhan <m.shulhan@gmail.com>
Micah Stetson <micah.stetson@gmail.com>
Michael Anthony Knyszek <mknyszek@google.com>
@@ -1654,6 +1654,7 @@ Nigel Kerr <nigel.kerr@gmail.com>
Nigel Tao <nigeltao@golang.org>
Nik Nyby <nnyby@columbia.edu>
Nikhil Benesch <nikhil.benesch@gmail.com>
+Nikita Gillmann <nikita@n0.is> <ng0@n0.is>
Nikita Kryuchkov <nkryuchkov10@gmail.com>
Nikita Vanyasin <nikita.vanyasin@gmail.com>
Niklas Schnelle <niklas.schnelle@gmail.com>
@@ -1788,6 +1789,7 @@ Pietro Gagliardi <pietro10@mac.com>
Piyush Mishra <piyush@codeitout.com>
Plekhanov Maxim <kishtatix@gmail.com>
Pontus Leitzler <leitzler@gmail.com>
+Prasanga Siripala <pj@pjebs.com.au>
Prasanna Swaminathan <prasanna@mediamath.com>
Prashant Agrawal <prashant.a.vjti@gmail.com>
Prashant Varanasi <prashant@prashantv.com>
@@ -2194,6 +2196,7 @@ Vadim Grek <vadimprog@gmail.com>
Vadim Vygonets <unixdj@gmail.com>
Val Polouchkine <vpolouch@justin.tv>
Valentin Vidic <vvidic@valentin-vidic.from.hr>
+Vee Zhang <veezhang@126.com> <vveezhang@gmail.com>
Vega Garcia Luis Alfonso <vegacom@gmail.com>
Venil Noronha <veniln@vmware.com>
Veselkov Konstantin <kostozyb@gmail.com>
diff --git a/api/go1.15.txt b/api/go1.15.txt
new file mode 100644
index 0000000000..b51837cf38
--- /dev/null
+++ b/api/go1.15.txt
@@ -0,0 +1,132 @@
+pkg bufio, var ErrBadReadCount error
+pkg crypto, method (Hash) String() string
+pkg crypto/ecdsa, func SignASN1(io.Reader, *PrivateKey, []uint8) ([]uint8, error)
+pkg crypto/ecdsa, func VerifyASN1(*PublicKey, []uint8, []uint8) bool
+pkg crypto/ecdsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
+pkg crypto/ecdsa, method (*PublicKey) Equal(crypto.PublicKey) bool
+pkg crypto/ed25519, method (PrivateKey) Equal(crypto.PrivateKey) bool
+pkg crypto/ed25519, method (PublicKey) Equal(crypto.PublicKey) bool
+pkg crypto/elliptic, func MarshalCompressed(Curve, *big.Int, *big.Int) []uint8
+pkg crypto/elliptic, func UnmarshalCompressed(Curve, []uint8) (*big.Int, *big.Int)
+pkg crypto/rsa, method (*PrivateKey) Equal(crypto.PrivateKey) bool
+pkg crypto/rsa, method (*PublicKey) Equal(crypto.PublicKey) bool
+pkg crypto/tls, method (*Dialer) Dial(string, string) (net.Conn, error)
+pkg crypto/tls, method (*Dialer) DialContext(context.Context, string, string) (net.Conn, error)
+pkg crypto/tls, method (ClientAuthType) String() string
+pkg crypto/tls, method (CurveID) String() string
+pkg crypto/tls, method (SignatureScheme) String() string
+pkg crypto/tls, type Config struct, VerifyConnection func(ConnectionState) error
+pkg crypto/tls, type Dialer struct
+pkg crypto/tls, type Dialer struct, Config *Config
+pkg crypto/tls, type Dialer struct, NetDialer *net.Dialer
+pkg crypto/x509, func CreateRevocationList(io.Reader, *RevocationList, *Certificate, crypto.Signer) ([]uint8, error)
+pkg crypto/x509, type RevocationList struct
+pkg crypto/x509, type RevocationList struct, ExtraExtensions []pkix.Extension
+pkg crypto/x509, type RevocationList struct, NextUpdate time.Time
+pkg crypto/x509, type RevocationList struct, Number *big.Int
+pkg crypto/x509, type RevocationList struct, RevokedCertificates []pkix.RevokedCertificate
+pkg crypto/x509, type RevocationList struct, SignatureAlgorithm SignatureAlgorithm
+pkg crypto/x509, type RevocationList struct, ThisUpdate time.Time
+pkg database/sql, method (*DB) SetConnMaxIdleTime(time.Duration)
+pkg database/sql, method (*Row) Err() error
+pkg database/sql, type DBStats struct, MaxIdleTimeClosed int64
+pkg database/sql/driver, type Validator interface { IsValid }
+pkg database/sql/driver, type Validator interface, IsValid() bool
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER = 4096
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_APPCONTAINER ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE = 64
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY = 128
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_FORCE_INTEGRITY ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF = 16384
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_GUARD_CF ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA = 32
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_HIGH_ENTROPY_VA ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND = 2048
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_BIND ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION = 512
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_ISOLATION ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH = 1024
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NO_SEH ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT = 256
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_NX_COMPAT ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE = 32768
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_TERMINAL_SERVER_AWARE ideal-int
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER = 8192
+pkg debug/pe, const IMAGE_DLLCHARACTERISTICS_WDM_DRIVER ideal-int
+pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE = 256
+pkg debug/pe, const IMAGE_FILE_32BIT_MACHINE ideal-int
+pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM = 16
+pkg debug/pe, const IMAGE_FILE_AGGRESIVE_WS_TRIM ideal-int
+pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI = 32768
+pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_HI ideal-int
+pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO = 128
+pkg debug/pe, const IMAGE_FILE_BYTES_REVERSED_LO ideal-int
+pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED = 512
+pkg debug/pe, const IMAGE_FILE_DEBUG_STRIPPED ideal-int
+pkg debug/pe, const IMAGE_FILE_DLL = 8192
+pkg debug/pe, const IMAGE_FILE_DLL ideal-int
+pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE = 2
+pkg debug/pe, const IMAGE_FILE_EXECUTABLE_IMAGE ideal-int
+pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE = 32
+pkg debug/pe, const IMAGE_FILE_LARGE_ADDRESS_AWARE ideal-int
+pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED = 4
+pkg debug/pe, const IMAGE_FILE_LINE_NUMS_STRIPPED ideal-int
+pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED = 8
+pkg debug/pe, const IMAGE_FILE_LOCAL_SYMS_STRIPPED ideal-int
+pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP = 2048
+pkg debug/pe, const IMAGE_FILE_NET_RUN_FROM_SWAP ideal-int
+pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED = 1
+pkg debug/pe, const IMAGE_FILE_RELOCS_STRIPPED ideal-int
+pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP = 1024
+pkg debug/pe, const IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP ideal-int
+pkg debug/pe, const IMAGE_FILE_SYSTEM = 4096
+pkg debug/pe, const IMAGE_FILE_SYSTEM ideal-int
+pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY = 16384
+pkg debug/pe, const IMAGE_FILE_UP_SYSTEM_ONLY ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION = 10
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_APPLICATION ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER = 11
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM = 13
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_ROM ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER = 12
+pkg debug/pe, const IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE = 1
+pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS = 8
+pkg debug/pe, const IMAGE_SUBSYSTEM_NATIVE_WINDOWS ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI = 5
+pkg debug/pe, const IMAGE_SUBSYSTEM_OS2_CUI ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI = 7
+pkg debug/pe, const IMAGE_SUBSYSTEM_POSIX_CUI ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN = 0
+pkg debug/pe, const IMAGE_SUBSYSTEM_UNKNOWN ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION = 16
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_BOOT_APPLICATION ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI = 9
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CE_GUI ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI = 3
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_CUI ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI = 2
+pkg debug/pe, const IMAGE_SUBSYSTEM_WINDOWS_GUI ideal-int
+pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX = 14
+pkg debug/pe, const IMAGE_SUBSYSTEM_XBOX ideal-int
+pkg go/printer, const StdFormat = 16
+pkg go/printer, const StdFormat Mode
+pkg math/big, method (*Int) FillBytes([]uint8) []uint8
+pkg net, method (*Resolver) LookupIP(context.Context, string, string) ([]IP, error)
+pkg net/url, method (*URL) EscapedFragment() string
+pkg net/url, method (*URL) Redacted() string
+pkg net/url, type URL struct, RawFragment string
+pkg os, method (*File) ReadFrom(io.Reader) (int64, error)
+pkg os, var ErrDeadlineExceeded error
+pkg regexp, method (*Regexp) SubexpIndex(string) int
+pkg strconv, func FormatComplex(complex128, uint8, int, int) string
+pkg strconv, func ParseComplex(string, int) (complex128, error)
+pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)
+pkg testing, method (*B) TempDir() string
+pkg testing, method (*T) Deadline() (time.Time, bool)
+pkg testing, method (*T) TempDir() string
+pkg testing, type TB interface, TempDir() string
+pkg time, method (*Ticker) Reset(Duration)
diff --git a/api/next.txt b/api/next.txt
index 442c29a416..e69de29bb2 100644
--- a/api/next.txt
+++ b/api/next.txt
@@ -1,3 +0,0 @@
-pkg testing, method (*T) Deadline() (time.Time, bool)
-pkg time, method (*Ticker) Reset(Duration)
-pkg sync, method (*Map) LoadAndDelete(interface{}) (interface{}, bool)
diff --git a/doc/contribute.html b/doc/contribute.html
index 5fefac6bba..03d02c9d75 100644
--- a/doc/contribute.html
+++ b/doc/contribute.html
@@ -174,7 +174,7 @@ The main Go repository is located at
a Git server hosted by Google.
Authentication on the web server is made through your Google account, but
you also need to configure <code>git</code> on your computer to access it.
-Follow this steps:
+Follow these steps:
</p>
<ol>
@@ -263,6 +263,24 @@ a new issue</a> or by claiming
an <a href="https://golang.org/issues">existing one</a>.
</p>
+<h3 id="where">Where to contribute</h3>
+
+<p>
+The Go project consists of the main
+<a href="https://go.googlesource.com/go">go</a> repository, which contains the
+source code for the Go language, as well as many golang.org/x/... repostories.
+These contain the various tools and infrastructure that support Go. For
+example, <a href="https://go.googlesource.com/pkgsite">golang.org/x/pkgsite</a>
+is for <a href="https://pkg.go.dev">pkg.go.dev</a>,
+<a href="https://go.googlesource.com/playground">golang.org/x/playground</a>
+is for the Go playground, and
+<a href="https://go.googlesource.com/tools">golang.org/x/tools</a> contains
+a variety of Go tools, including the Go language server,
+<a href="https://golang.org/s/gopls">gopls</a>. You can see a
+list of all the golang.org/x/... repositories on
+<a href="https://go.googlesource.com">go.googlesource.com</a>.
+</p>
+
<h3 id="check_tracker">Check the issue tracker</h3>
<p>
@@ -273,6 +291,13 @@ Issues are triaged to categorize them and manage the workflow.
</p>
<p>
+The majority of the golang.org/x/... repos also use the main Go
+issue tracker. However, a few of these repositories manage their issues
+separately, so please be sure to check the right tracker for the repository to
+which you would like to contribute.
+</p>
+
+<p>
Most issues will be marked with one of the following workflow labels:
</p>
@@ -285,7 +310,7 @@ Most issues will be marked with one of the following workflow labels:
<b>NeedsDecision</b>: the issue is relatively well understood, but the
Go team hasn't yet decided the best way to address it.
It would be better to wait for a decision before writing code.
- If you are interested on working on an issue in this state,
+ If you are interested in working on an issue in this state,
feel free to "ping" maintainers in the issue's comments
if some time has passed without a decision.
</li>
@@ -329,11 +354,16 @@ the code review tool is not the place for high-level discussions.
<p>
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 they will
-not be merged until the freeze is over.
+href="https://golang.org/wiki/Go-Release-Cycle">six-month development cycle</a>
+for the main Go repository. 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 they will
+not be merged until the freeze is over. The freeze applies to the entire main
+repository as well as to the code in golang.org/x/... repositories that is
+needed to build the binaries included in the release. See the lists of packages
+vendored into
+<a href="https://github.com/golang/go/blob/master/src/vendor/modules.txt">the standard library</a>
+and the <a href="https://github.com/golang/go/blob/master/src/cmd/vendor/modules.txt"><code>go</code> command</a>.
</p>
<p>
@@ -408,13 +438,29 @@ This is an overview of the overall process:
<ul>
<li>
-<b>Step 1:</b> Clone the Go source code from <code>go.googlesource.com</code>
-and make sure it's stable by compiling and testing it once:
+<b>Step 1:</b> Clone the source code from <code>go.googlesource.com</code> and
+make sure it's stable by compiling and testing it once.
+
+<p>If you're making a change to the
+<a href="https://go.googlesource.com/go">main Go repository</a>:</p>
+
<pre>
$ git clone https://go.googlesource.com/go
$ cd go/src
$ ./all.bash # compile and test
</pre>
+
+<p>
+If you're making a change to one of the golang.org/x/... repositories
+(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a>,
+in this example):
+</p>
+
+<pre>
+$ git clone https://go.googlesource.com/tools
+$ cd tools
+$ go test ./... # compile and test
+</pre>
</li>
<li>
@@ -434,10 +480,18 @@ $ [etc.]
</li>
<li>
-<b>Step 3:</b> Test your changes, re-running <code>all.bash</code>.
+<b>Step 3:</b> Test your changes, either by running the tests in the package
+you edited or by re-running <code>all.bash</code>.
+
+<p>In the main Go repository:</p>
<pre>
$ ./all.bash # recompile and test
</pre>
+
+<p>In a golang.org/x/... repository:</p>
+<pre>
+$ go test ./... # recompile and test
+</pre>
</li>
<li>
@@ -465,7 +519,7 @@ The rest of this section describes these steps in more detail.
</p>
-<h3 id="checkout_go">Step 1: Clone the Go source code</h3>
+<h3 id="checkout_go">Step 1: Clone the source code</h3>
<p>
In addition to a recent Go installation, you need to have a local copy of the source
@@ -475,11 +529,19 @@ you want as long as it's outside your <code>GOPATH</code>.
Clone from <code>go.googlesource.com</code> (not GitHub):
</p>
+<p>Main Go repository:</p>
<pre>
$ git clone https://go.googlesource.com/go
$ cd go
</pre>
+<p>golang.org/x/... repository</p>
+(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a> in this example):
+<pre>
+$ git clone https://go.googlesource.com/tools
+$ cd tools
+</pre>
+
<h3 id="make_branch">Step 2: Prepare changes in a new branch</h3>
<p>
@@ -543,9 +605,13 @@ into a single one.
<p>
You've <a href="code.html">written and tested your code</a>, but
before sending code out for review, run <i>all the tests for the whole
-tree</i> to make sure the changes don't break other packages or programs:
+tree</i> to make sure the changes don't break other packages or programs.
</p>
+<h4 id="test-gorepo">In the main Go repository</h4>
+
+<p>This can be done by running <code>all.bash</code>:</p>
+
<pre>
$ cd go/src
$ ./all.bash
@@ -574,6 +640,33 @@ See also
the section on how to <a href="#quick_test">test your changes quickly</a>.
</p>
+<h4 id="test-xrepo">In the golang.org/x/... repositories</h4>
+
+<p>
+Run the tests for the entire repository
+(<a href="https://go.googlesource.com/tools">golang.org/x/tools</a>,
+in this example):
+</p>
+
+<pre>
+$ cd tools
+$ go test ./...
+</pre>
+
+<p>
+If you're concerned about the build status,
+you can check the <a href="https://build.golang.org">Build Dashboard</a>.
+Test failures may also be caught by the TryBots in code review.
+</p>
+
+<p>
+Some repositories, like
+<a href="https://go.googlesource.com/vscode-go">golang.org/x/vscode-go</a> will
+have different testing infrastructures, so always check the documentation
+for the repository in which you are working. The README file in the root of the
+repository will usually have this information.
+</p>
+
<h3 id="mail">Step 4: Send changes for review</h3>
<p>
@@ -720,10 +813,10 @@ when the change is applied.
</p>
<p>
-If you are sending a change against a subrepository, you must use
+If you are sending a change against a golang.org/x/... repository, you must use
the fully-qualified syntax supported by GitHub to make sure the change is
-linked to the issue in the main repository, not the subrepository.
-All issues are tracked in the main repository's issue tracker.
+linked to the issue in the main repository, not the x/ repository.
+Most issues are tracked in the main repository's issue tracker.
The correct form is "Fixes golang/go#159".
</p>
@@ -1070,25 +1163,6 @@ $ $GODIR/bin/go run run.go
</pre>
</ul>
-<h3 id="subrepos">Contributing to subrepositories (golang.org/x/...)</h3>
-
-<p>
-If you are contributing a change to a subrepository, obtain the
-Go package using <code>go get</code>.
-For example, to contribute
-to <code>golang.org/x/oauth2</code>, check out the code by running:
-</p>
-
-<pre>
-$ go get -d golang.org/x/oauth2/...
-</pre>
-
-<p>
-Then, change your directory to the package's source directory
-(<code>$GOPATH/src/golang.org/x/oauth2</code>), and follow the
-normal contribution flow.
-</p>
-
<h3 id="cc">Specifying a reviewer / CCing others</h3>
@@ -1209,5 +1283,5 @@ $ git codereview mail HEAD
<p>
Make sure to explicitly specify <code>HEAD</code>, which is usually not required when sending
-single changes.
+single changes. More details can be found in the <a href="https://pkg.go.dev/golang.org/x/review/git-codereview?tab=doc#hdr-Multiple_Commit_Work_Branches">git-codereview documentation</a>.
</p>
diff --git a/doc/editors.html b/doc/editors.html
index 4ff35a58fc..22927bfa20 100644
--- a/doc/editors.html
+++ b/doc/editors.html
@@ -20,7 +20,7 @@ editing, navigation, testing, and debugging experience.
<ul>
<li><a href="https://github.com/fatih/vim-go">vim</a>: vim-go plugin provides Go programming language support</li>
-<li><a href="https://marketplace.visualstudio.com/items?itemName=lukehoban.Go">Visual Studio Code</a>:
+<li><a href="https://marketplace.visualstudio.com/items?itemName=ms-vscode.Go">Visual Studio Code</a>:
Go extension provides support for the Go programming language</li>
<li><a href="https://www.jetbrains.com/go">GoLand</a>: GoLand is distributed either as a standalone IDE
or as a plugin for IntelliJ IDEA Ultimate</li>
diff --git a/doc/effective_go.html b/doc/effective_go.html
index 9be6bc7cb0..7620402984 100644
--- a/doc/effective_go.html
+++ b/doc/effective_go.html
@@ -2336,10 +2336,9 @@ of the request from the client.
</p>
<p>
For brevity, let's ignore POSTs and assume HTTP requests are always
-GETs; that simplification does not affect the way the handlers are
-set up. Here's a trivial but complete implementation of a handler to
-count the number of times the
-page is visited.
+GETs; that simplification does not affect the way the handlers are set up.
+Here's a trivial implementation of a handler to count the number of times
+the page is visited.
</p>
<pre>
// Simple counter server.
@@ -2355,6 +2354,11 @@ func (ctr *Counter) ServeHTTP(w http.ResponseWriter, req *http.Request) {
<p>
(Keeping with our theme, note how <code>Fprintf</code> can print to an
<code>http.ResponseWriter</code>.)
+In a real server, access to <code>ctr.n</code> would need protection from
+concurrent access.
+See the <code>sync</code> and <code>atomic</code> packages for suggestions.
+</p>
+<p>
For reference, here's how to attach such a server to a node on the URL tree.
</p>
<pre>
diff --git a/doc/gccgo_install.html b/doc/gccgo_install.html
index 08415a871b..c478a9ea2d 100644
--- a/doc/gccgo_install.html
+++ b/doc/gccgo_install.html
@@ -79,15 +79,13 @@ release.
<h2 id="Source_code">Source code</h2>
<p>
-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="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
-repository: <code>svn://gcc.gnu.org/svn/gcc/branches/gccgo</code>.
+If you cannot use a release, or prefer to build gccgo for yourself, the
+gccgo source code is accessible via Git. The GCC web site has
+<a href="https://gcc.gnu.org/git.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 the
+<code>devel/gccgo</code> branch of the main GCC code repository:
+<code>git://gcc.gnu.org/git/gcc.git</code>.
This branch is periodically updated with stable Go compiler sources.
</p>
@@ -139,13 +137,10 @@ which you have write access):
</p>
<pre>
-cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src login
-[password is "anoncvs"]
-[The next command will create a directory named src, not binutils]
-cvs -z 9 -d :pserver:anoncvs@sourceware.org:/cvs/src co binutils
+git clone git://sourceware.org/git/binutils-gdb.git
mkdir binutils-objdir
cd binutils-objdir
-../src/configure --enable-gold=default --prefix=/opt/gold
+../binutils-gdb/configure --enable-gold=default --prefix=/opt/gold
make
make install
</pre>
@@ -176,7 +171,7 @@ described above):
</p>
<pre>
-svn checkout svn://gcc.gnu.org/svn/gcc/branches/gccgo gccgo
+git clone --branch devel/gccgo git://gcc.gnu.org/git/gcc.git gccgo
mkdir objdir
cd objdir
../gccgo/configure --prefix=/opt/gccgo --enable-languages=c,c++,go --with-ld=/opt/gold/bin/ld
diff --git a/doc/go1.10.html b/doc/go1.10.html
index 41db36ab1e..853f874ded 100644
--- a/doc/go1.10.html
+++ b/doc/go1.10.html
@@ -30,7 +30,7 @@ adds <a href="#test">caching of successful test results</a>,
runs <a href="#test-vet">vet automatically during tests</a>,
and
permits <a href="#cgo">passing string values directly between Go and C using cgo</a>.
-A new <a href="#cgo">compiler option whitelist</a> may cause
+A new <a href="#cgo">hard-coded set of safe compiler options</a> may cause
unexpected <a href="https://golang.org/s/invalidflag"><code>invalid
flag</code></a> errors in code that built successfully with older
releases.
@@ -267,7 +267,7 @@ and the <a href="/cmd/test2json/">test2json documentation</a>.
<p>
Options specified by cgo using <code>#cgo CFLAGS</code> and the like
-are now checked against a whitelist of permitted options.
+are now checked against a list of permitted options.
This closes a security hole in which a downloaded package uses
compiler options like
<span style="white-space: nowrap"><code>-fplugin</code></span>
diff --git a/doc/go1.14.html b/doc/go1.14.html
index 478035360a..35a9f3c2f3 100644
--- a/doc/go1.14.html
+++ b/doc/go1.14.html
@@ -466,7 +466,15 @@ Do not send CLs removing the interior tags from such phrases.
certificate, and letting the package automatically select the best one.
Note that the performance of this selection is going to be poor unless the
<a href="/pkg/crypto/tls/#Certificate.Leaf"><code>Certificate.Leaf</code></a>
- field is set.
+ field is set. The
+ <a href="/pkg/crypto/tls/#Config.NameToCertificate"><code>Config.NameToCertificate</code></a>
+ field, which only supports associating a single certificate with
+ a give name, is now deprecated and should be left as <code>nil</code>.
+ Similarly the
+ <a href="/pkg/crypto/tls/#Config.BuildNameToCertificate"><code>Config.BuildNameToCertificate</code></a>
+ method, which builds the <code>NameToCertificate</code> field
+ from the leaf certificates, is now deprecated and should not be
+ called.
</p>
<p><!-- CL 175517 -->
diff --git a/doc/go1.15.html b/doc/go1.15.html
index af0b3ba6ac..45ffec4b34 100644
--- a/doc/go1.15.html
+++ b/doc/go1.15.html
@@ -26,14 +26,20 @@ Do not send CLs removing the interior tags from such phrases.
<h2 id="language">Changes to the language</h2>
<p>
-TODO
+ There are no changes to the language.
</p>
<h2 id="ports">Ports</h2>
<h3 id="darwin">Darwin</h3>
-<p> <!-- golang.org/issue/37610, golang.org/issue/37611 -->
+<p>
+ As <a href="go1.14#darwin">announced</a> in the Go 1.14 release
+ notes, Go 1.15 requires macOS 10.12 Sierra or later; support for
+ previous versions has been discontinued.
+</p>
+
+<p> <!-- golang.org/issue/37610, golang.org/issue/37611, CL 227582, and CL 227198 -->
As <a href="/doc/go1.14#darwin">announced</a> in the Go 1.14 release
notes, Go 1.15 drops support for 32-bit binaries on macOS, iOS,
iPadOS, watchOS, and tvOS (the <code>darwin/386</code>
@@ -44,21 +50,52 @@ TODO
<h3 id="windows">Windows</h3>
<p> <!-- CL 214397 and CL 230217 -->
- Go 1.15 now generates Windows ASLR executables when -buildmode=pie
- cmd/link flag is provided. Go command uses -buildmode=pie by default
- on Windows.
+ Go now generates Windows ASLR executables when <code>-buildmode=pie</code>
+ cmd/link flag is provided. Go command uses <code>-buildmode=pie</code>
+ by default on Windows.
</p>
-<p>
-TODO
+<p><!-- CL 227003 -->
+ The <code>-race</code> and <code>-msan</code> flags now always
+ enable <code>-d=checkptr</code>, which checks uses
+ of <code>unsafe.Pointer</code>. This was previously the case on all
+ OSes except Windows.
</p>
-<h2 id="tools">Tools</h2>
+<p><!-- CL 211139 -->
+ Go-built DLLs no longer cause the process to exit when it receives a
+ signal (such as Ctrl-C at a terminal).
+</p>
-<p>
-TODO
+<h3 id="android">Android</h3>
+
+<p> <!-- CL 235017, golang.org/issue/38838 -->
+ When linking binaries for Android, Go 1.15 explicitly selects
+ the <code>lld</code> linker available in recent versions of the NDK.
+ The <code>lld</code> linker avoids crashes on some devices, and is
+ planned to become the default NDK linker in a future NDK version.
</p>
+<h3 id="openbsd">OpenBSD</h3>
+
+<p><!-- CL 234381 -->
+ Go 1.15 adds support for OpenBSD 6.7 on <code>GOARCH=arm</code>
+ and <code>GOARCH=arm64</code>. Previous versions of Go already
+ supported OpenBSD 6.7 on <code>GOARCH=386</code>
+ and <code>GOARCH=amd64</code>.
+</p>
+
+<h3 id="riscv">RISC-V</h3>
+
+<p> <!-- CL 226400, CL 226206, and others -->
+ There has been progress in improving the stability and performance
+ of the 64-bit RISC-V port on Linux (<code>GOOS=linux</code>,
+ <code>GOARCH=riscv64</code>). It also now supports asynchronous
+ preemption.
+</p>
+
+<h2 id="tools">Tools</h2>
+
<h3 id="go-command">Go command</h3>
<p><!-- golang.org/issue/37367 -->
@@ -73,10 +110,6 @@ TODO
back to <code>direct</code> in case of errors.
</p>
-<p>
-TODO
-</p>
-
<h4 id="go-test"><code>go</code> <code>test</code></h4>
<p><!-- https://golang.org/issue/36134 -->
@@ -112,27 +145,207 @@ TODO
<a href="https://golang.org/issue/36568">issue #36568</a>). The workaround is
not enabled by default because it is not safe to use when Go versions lower
than 1.14.2 and 1.13.10 are running concurrently with the same module cache.
- It can be enabled by explictly setting the environment variable
+ It can be enabled by explicitly setting the environment variable
<code>GODEBUG=modcacheunzipinplace=1</code>.
</p>
-<h2 id="runtime">Runtime</h2>
+<h3 id="vet">Vet</h3>
+
+<h4 id="vet-string-int">New warning for string(x)</h4>
+
+<p><!-- CL 212919, 232660 -->
+ The vet tool now warns about conversions of the
+ form <code>string(x)</code> where <code>x</code> has an integer type
+ other than <code>rune</code> or <code>byte</code>.
+ Experience with Go has shown that many conversions of this form
+ erroneously assume that <code>string(x)</code> evaluates to the
+ string representation of the integer <code>x</code>.
+ It actually evaluates to a string containing the UTF-8 encoding of
+ the value of <code>x</code>.
+ For example, <code>string(9786)</code> does not evaluate to the
+ string <code>"9786"</code>; it evaluates to the
+ string <code>"\xe2\x98\xba"</code>, or <code>"☺"</code>.
+</p>
+
+<p>
+ Code that is using <code>string(x)</code> correctly can be rewritten
+ to <code>string(rune(x))</code>.
+ Or, in some cases, calling <code>utf8.EncodeRune(buf, x)</code> with
+ a suitable byte slice <code>buf</code> may be the right solution.
+ Other code should most likely use <code>strconv.Itoa</code>
+ or <code>fmt.Sprint</code>.
+</p>
<p>
-TODO
+ This new vet check is enabled by default when
+ using <code>go</code> <code>test</code>.
+</p>
+
+<p>
+ We are considering prohibiting the conversion in a future release of Go.
+ That is, the language would change to only
+ permit <code>string(x)</code> for integer <code>x</code> when the
+ type of <code>x</code> is <code>rune</code> or <code>byte</code>.
+ Such a language change would not be backward compatible.
+ We are using this vet check as a first trial step toward changing
+ the language.
+</p>
+
+<h4 id="vet-impossible-interface">New warning for impossible interface conversions</h4>
+
+<p><!-- CL 218779, 232660 -->
+ The vet tool now warns about type assertions from one interface type
+ to another interface type when the type assertion will always fail.
+ This will happen if both interface types implement a method with the
+ same name but with a different type signature.
+</p>
+
+<p>
+ There is no reason to write a type assertion that always fails, so
+ any code that triggers this vet check should be rewritten.
+</p>
+
+<p>
+ This new vet check is enabled by default when
+ using <code>go</code> <code>test</code>.
+</p>
+
+<p>
+ We are considering prohibiting impossible interface type assertions
+ in a future release of Go.
+ Such a language change would not be backward compatible.
+ We are using this vet check as a first trial step toward changing
+ the language.
+</p>
+
+<h2 id="runtime">Runtime</h2>
+
+<p><!-- CL 221779 -->
+ If <code>panic</code> is invoked with a value whose type is derived from any
+ of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
+ <code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
+ <code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
+ then the value will be printed, instead of just its address.
+ Previously, this was only true for values of exactly these types.
+</p>
+
+<p><!-- CL 228900 -->
+ On a Unix system, if the <code>kill</code> command
+ or <code>kill</code> system call is used to send
+ a <code>SIGSEGV</code>, <code>SIGBUS</code>,
+ or <code>SIGFPE</code> signal to a Go program, and if the signal
+ is not being handled via
+ <a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
+ the Go program will now reliably crash with a stack trace.
+ In earlier releases the behavior was unpredictable.
+</p>
+
+<p><!-- CL 221182, CL 229998 -->
+ Allocation of small objects now performs much better at high core
+ counts, and has lower worst-case latency.
+</p>
+
+<p><!-- CL 216401 -->
+ Converting a small integer value into an interface value no longer
+ causes allocation.
+</p>
+
+<p><!-- CL 216818 -->
+ Non-blocking receives on closed channels now perform as well as
+ non-blocking receives on open channels.
</p>
<h2 id="compiler">Compiler</h2>
-<p><!-- https://golang.org/cl/229578 -->
+<p><!-- CL 229578 -->
Package <code>unsafe</code>'s <a href="/pkg/unsafe/#Pointer">safety
rules</a> allow converting an <code>unsafe.Pointer</code>
into <code>uintptr</code> when calling certain
functions. Previously, in some cases, the compiler allowed multiple
- chained conversions (for example, <code>syscall.Syscall(…,
- uintptr(uintptr(ptr)), …)</code>). The compiler now requires exactly
- one conversion. Code that used multiple conversions should be
- updated to satisfy the safety rules.
+ chained conversions (for example, <code>syscall.Syscall(…,</code>
+ <code>uintptr(uintptr(ptr)),</code> <code>…)</code>). The compiler
+ now requires exactly one conversion. Code that used multiple
+ conversions should be updated to satisfy the safety rules.
+</p>
+
+<p><!-- CL 230544, CL 231397 -->
+ Go 1.15 reduces typical binary sizes by around 5% compared to Go
+ 1.14 by eliminating certain types of GC metadata and more
+ aggressively eliminating unused type metadata.
+</p>
+
+<p><!-- CL 219357, CL 231600 -->
+ The toolchain now mitigates
+ <a href="https://www.intel.com/content/www/us/en/support/articles/000055650/processors.html">Intel
+ CPU erratum SKX102</a> on <code>GOARCH=amd64</code> by aligning
+ functions to 32 byte boundaries and padding jump instructions. While
+ this padding increases binary sizes, this is more than made up for
+ by the binary size improvements mentioned above.
+</p>
+
+<p><!-- CL 222661 -->
+ Go 1.15 adds a <code>-spectre</code> flag to both the
+ compiler and the assembler, to allow enabling Spectre mitigations.
+ These should almost never be needed and are provided mainly as a
+ “defense in depth” mechanism.
+ See the <a href="https://github.com/golang/go/wiki/Spectre">Spectre wiki page</a> for details.
+</p>
+
+<p><!-- CL 228578 -->
+ The compiler now rejects <code>//go:</code> compiler directives that
+ have no meaning for the declaration they are applied to with a
+ "misplaced compiler directive" error. Such misapplied directives
+ were broken before, but were silently ignored by the compiler.
+</p>
+
+<p><!-- CL 206658, CL 205066 -->
+ The compiler's <code>-json</code> optimization logging now reports
+ large (>= 128 byte) copies and includes explanations of escape
+ analysis decisions.
+</p>
+
+<h2 id="linker">Linker</h2>
+
+<p>
+ This release includes substantial improvements to the Go linker,
+ which reduce linker resource usage (both time and memory) and
+ improve code robustness/maintainability.
+</p>
+
+<p>
+ For a representative set of large Go programs, linking is 20% faster
+ and requires 30% less memory on average, for <code>ELF</code>-based
+ OSes (Linux, FreeBSD, NetBSD, OpenBSD, Dragonfly, and Solaris)
+ running on <code>amd64</code> architectures, with more modest
+ improvements for other architecture/OS combinations.
+</p>
+
+<p>
+ The key contributors to better linker performance are a newly
+ redesigned object file format, and a revamping of internal
+ phases to increase concurrency (for example, applying relocations to
+ symbols in parallel). Object files in Go 1.15 are slightly larger
+ than their 1.14 equivalents.
+</p>
+
+<p>
+ These changes are part of a multi-release project
+ to <a href="https://golang.org/s/better-linker">modernize the Go
+ linker</a>, meaning that there will be additional linker
+ improvements expected in future releases.
+</p>
+
+<p><!-- CL 207877 -->
+ TODO: <a href="https://golang.org/cl/207877">https://golang.org/cl/207877</a>: Revert -buildmode=pie to internal linking.
+ The linker defaults to internal linking mode for PIE on linux/amd64 and linux/arm64, which does require a C linker.
+</p>
+
+<h2 id="objdump">Objdump</h2>
+
+<p><!-- CL 225459 -->
+ The <a href="/cmd/objdump/">objdump</a> tool now supports
+ disassembling in GNU assembler syntax with the <code>-gnu</code>
+ flag.
</p>
<h2 id="library">Core library</h2>
@@ -151,25 +364,15 @@ TODO
Either approach increases the size of the program by about 800 KB.
</p>
-<p>
-TODO
-</p>
+<h3 id="cgo">Cgo</h3>
-<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
- <dd>
- <p><!-- golang.org/issue/28135 -->
- The <code>testing.T</code> type now has a <code>Deadline</code> method
- that reports the time at which the test binary will have exceeded its
- timeout.
- </p>
- <p><!-- golang.org/issue/34129 -->
- A <code>TestMain</code> function is no longer required to call
- <code>os.Exit</code>. If a <code>TestMain</code> function returns,
- the test binary will call <code>os.Exit</code> with the value returned
- by <code>m.Run</code>.
- </p>
- </dd>
-</dl><!-- testing -->
+<p><!-- CL 235817 -->
+ Go 1.15 will translate the C type <code>EGLConfig</code> to the
+ Go type <code>uintptr</code>. This change is similar to how Go
+ 1.12 and newer treats <code>EGLDisplay</code>, Darwin's CoreFoundation and
+ Java's JNI types. See the <a href="/cmd/cgo/#hdr-Special_cases">cgo
+ documentation</a> for more information.
+</p>
<h3 id="minor_library_changes">Minor changes to the library</h3>
@@ -179,27 +382,261 @@ TODO
in mind.
</p>
-<p>
-TODO
-</p>
+<dl id="bufio"><dt><a href="/pkg/bufio/">bufio</a></dt>
+ <dd>
+ <p><!-- CL 225357, CL 225557 -->
+ When a <a href="/pkg/bufio/#Scanner"><code>Scanner</code></a> is
+ used with an invalid
+ <a href="/pkg/io/#Reader"><code>io.Reader</code></a> that
+ incorrectly returns a negative number from <code>Read</code>,
+ the <code>Scanner</code> will no longer panic, but will instead
+ return the new error
+ <a href="/pkg/bufio/#ErrBadReadCount"><code>ErrBadReadCount</code></a>.
+ </p>
+ </dd>
+</dl><!-- bufio -->
+
+<dl id="crypto"><dt><a href="/pkg/crypto/">crypto</a></dt>
+ <dd>
+ <p><!-- CL 231417, CL 225460 -->
+ The <code>PrivateKey</code> and <code>PublicKey</code> types in the
+ <a href="/pkg/crypto/rsa/"><code>crypto/rsa</code></a>,
+ <a href="/pkg/crypto/ecdsa/"><code>crypto/ecdsa</code></a>, and
+ <a href="/pkg/crypto/ed25519/"><code>crypto/ed25519</code></a> packages
+ now have an <code>Equal</code> method to compare keys for equivalence
+ or to make type-safe interfaces for public keys. The method signature
+ is compatible with
+ <a href="https://pkg.go.dev/github.com/google/go-cmp/cmp#Equal"><code>go-cmp</code>'s
+ definition of equality</a>.
+ </p>
+
+ <p><!-- CL 224937 -->
+ <a href="/pkg/crypto/#Hash"><code>Hash</code></a> now implements
+ <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
+ </p>
+ </dd>
+</dl><!-- crypto -->
-<dl id="crypto/tls"><dt><a href="/crypto/tls/">crypto/tls</a></dt>
+<dl id="crypto/ecdsa"><dt><a href="/pkg/crypto/ecdsa/">crypto/ecdsa</a></dt>
+ <dd>
+ <p><!-- CL 217940 -->
+ The new <a href="/pkg/crypto/ecdsa/#SignASN1"><code>SignASN1</code></a>
+ and <a href="/pkg/crypto/ecdsa/#VerifyASN1"><code>VerifyASN1</code></a>
+ functions allow generating and verifying ECDSA signatures in the standard
+ ASN.1 DER encoding.
+ </p>
+ </dd>
+</dl><!-- crypto/ecdsa -->
+
+<dl id="crypto/elliptic"><dt><a href="/pkg/crypto/elliptic/">crypto/elliptic</a></dt>
+ <dd>
+ <p><!-- CL 202819 -->
+ The new <a href="/pkg/crypto/elliptic/#MarshalCompressed"><code>MarshalCompressed</code></a>
+ and <a href="/pkg/crypto/elliptic/#UnmarshalCompressed"><code>UnmarshalCompressed</code></a>
+ functions allow encoding and decoding NIST elliptic curve points in compressed format.
+ </p>
+ </dd>
+</dl><!-- crypto/elliptic -->
+
+<dl id="crypto/rsa"><dt><a href="/pkg/crypto/rsa/">crypto/rsa</a></dt>
+ <dd>
+ <p><!-- CL 226203 -->
+ <a href="/pkg/crypto/rsa/#VerifyPKCS1v15"><code>VerifyPKCS1v15</code></a>
+ now rejects invalid short signatures with missing leading zeroes, according to RFC 8017.
+ </p>
+ </dd>
+</dl><!-- crypto/rsa -->
+
+<dl id="crypto/tls"><dt><a href="/pkg/crypto/tls/">crypto/tls</a></dt>
<dd>
<p><!-- CL 214977 -->
The new
<a href="/pkg/crypto/tls/#Dialer"><code>Dialer</code></a>
type and its
<a href="/pkg/crypto/tls/#Dialer.DialContext"><code>DialContext</code></a>
- method permits using a context to both connect and handshake with a TLS server.
+ method permit using a context to both connect and handshake with a TLS server.
+ </p>
+
+ <p><!-- CL 229122 -->
+ The new
+ <a href="/pkg/crypto/tls/#Config.VerifyConnection"><code>VerifyConnection</code></a>
+ callback on the <a href="/pkg/crypto/tls/#Config"><code>Config</code></a> type
+ allows custom verification logic for every connection. It has access to the
+ <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+ which includes peer certificates, SCTs, and stapled OCSP responses.
+ </p>
+
+ <p><!-- CL 230679 -->
+ Auto-generated session ticket keys are now automatically rotated every 24 hours,
+ with a lifetime of 7 days, to limit their impact on forward secrecy.
+ </p>
+
+ <p><!-- CL 231317 -->
+ Session ticket lifetimes in TLS 1.2 and earlier, where the session keys
+ are reused for resumed connections, are now limited to 7 days, also to
+ limit their impact on forward secrecy.
+ </p>
+
+ <p><!-- CL 231038 -->
+ The client-side downgrade protection checks specified in RFC 8446 are now
+ enforced. This has the potential to cause connection errors for clients
+ encountering middleboxes that behave like unauthorized downgrade attacks.
+ </p>
+
+ <p><!-- CL 208226 -->
+ <a href="/pkg/crypto/tls/#SignatureScheme"><code>SignatureScheme</code></a>,
+ <a href="/pkg/crypto/tls/#CurveID"><code>CurveID</code></a>, and
+ <a href="/pkg/crypto/tls/#ClientAuthType"><code>ClientAuthType</code></a>
+ now implement <a href="/pkg/fmt/#Stringer"><code>fmt.Stringer</code></a>.
+ </p>
+
+ <p><!-- CL 236737 -->
+ The <a href="/pkg/crypto/tls/#ConnectionState"><code>ConnectionState</code></a>
+ fields <code>OCSPResponse</code> and <code>SignedCertificateTimestamps</code>
+ are now repopulated on client-side resumed connections.
</p>
</dd>
-</dl>
+</dl><!-- crypto/tls -->
+
+<dl id="crypto/x509"><dt><a href="/pkg/crypto/x509/">crypto/x509</a></dt>
+ <dd>
+ <p><!-- CL 231378, CL 231380, CL 231381 -->
+ If either the name on the certificate or the name being verified (with
+ <a href="/pkg/crypto/x509/#VerifyOptions.DNSName"><code>VerifyOptions.DNSName</code></a>
+ or <a href="/pkg/crypto/x509/#Certificate.VerifyHostname"><code>VerifyHostname</code></a>)
+ are invalid, they will now be compared case-insensitively without further
+ processing (without honoring wildcards or stripping trailing dots).
+ Invalid names include those with any characters other than letters,
+ digits, hyphens and underscores, those with empty labels, and names on
+ certificates with trailing dots.
+ </p>
+
+ <p><!-- CL 231379 -->
+ The deprecated, legacy behavior of treating the <code>CommonName</code>
+ field as a hostname when no Subject Alternative Names are present is now
+ disabled by default. It can be temporarily re-enabled by adding the value
+ <code>x509ignoreCN=0</code> to the <code>GODEBUG</code> environment
+ variable. If the <code>CommonName</code> is an invalid hostname, it's
+ always ignored.
+ </p>
+
+ <p><!-- CL 217298 -->
+ The new <a href="/pkg/crypto/x509/#CreateRevocationList"><code>CreateRevocationList</code></a>
+ function and <a href="/pkg/crypto/x509/#RevocationList"><code>RevocationList</code></a> type
+ allow creating RFC 5280-compliant X.509 v2 Certificate Revocation Lists.
+ </p>
+
+ <p><!-- CL 227098 -->
+ <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+ now automatically generates the <code>SubjectKeyId</code> if the template
+ is a CA and doesn't explicitly specify one.
+ </p>
+
+ <p><!-- CL 228777 -->
+ <a href="/pkg/crypto/x509/#CreateCertificate"><code>CreateCertificate</code></a>
+ now returns an error if the template specifies <code>MaxPathLen</code> but is not a CA.
+ </p>
+
+ <p><!-- CL 205237 -->
+ On Unix systems other than macOS, the <code>SSL_CERT_DIR</code>
+ environment variable can now be a colon-separated list.
+ </p>
+
+ <p><!-- CL 227037 -->
+ On macOS, binaries are now always linked against
+ <code>Security.framework</code> to extract the system trust roots,
+ regardless of whether cgo is available. The resulting behavior should be
+ more consistent with the OS verifier.
+ </p>
+ </dd>
+</dl><!-- crypto/x509 -->
+
+<dl id="crypto/x509/pkix"><dt><a href="/pkg/crypto/x509/pkix/">crypto/x509/pkix</a></dt>
+ <dd>
+ <p><!-- CL 229864 -->
+ <a href="/pkg/crypto/x509/pkix/#Name.String"><code>Name.String</code></a>
+ now prints non-standard attributes from
+ <a href="/pkg/crypto/x509/pkix/#Name.Names"><code>Names</code></a> if
+ <a href="/pkg/crypto/x509/pkix/#Name.ExtraNames"><code>ExtraNames</code></a> is empty.
+ </p>
+ </dd>
+</dl><!-- crypto/x509/pkix -->
+
+<dl id="database/sql"><dt><a href="/pkg/database/sql/">database/sql</a></dt>
+ <dd>
+ <p><!-- CL 145758 -->
+ The new <a href="/pkg/database/sql/#DB.SetConnMaxIdleTime"><code>DB.SetConnMaxIdleTime</code></a>
+ method allows removing a connection from the connection pool after
+ it has been idle for a period of time, without regard to the total
+ lifespan of the connection. The <a href="/pkg/database/sql/#DBStats.MaxIdleTimeClosed"><code>DBStats.MaxIdleTimeClosed</code></a>
+ field shows the total number of connections closed due to
+ <code>DB.SetConnMaxIdleTime</code>.
+ </p>
+
+ <p><!-- CL 214317 -->
+ The new <a href="/pkg/database/sql/#Row.Err"><code>Row.Err</code></a> getter
+ allows checking for query errors without calling
+ <code>Row.Scan</code>.
+ </p>
+ </dd>
+</dl><!-- database/sql -->
+
+<dl id="database/sql/driver"><dt><a href="/pkg/database/sql/driver/">database/sql/driver</a></dt>
+ <dd>
+ <p><!-- CL 174122 -->
+ The new <a href="/pkg/database/sql/driver/#Validator"><code>Validator</code></a>
+ interface may be implemented by <code>Conn</code> to allow drivers
+ to signal if a connection is valid or if it should be discarded.
+ </p>
+ </dd>
+</dl><!-- database/sql/driver -->
+
+<dl id="debug/pe"><dt><a href="/pkg/debug/pe/">debug/pe</a></dt>
+ <dd>
+ <p><!-- CL 222637 -->
+ The package now defines the
+ <code>IMAGE_FILE</code>, <code>IMAGE_SUBSYSTEM</code>,
+ and <code>IMAGE_DLLCHARACTERISTICS</code> constants used by the
+ PE file format.
+ </p>
+ </dd>
+</dl><!-- debug/pe -->
+
+<dl id="encoding/asn1"><dt><a href="/pkg/encoding/asn1/">encoding/asn1</a></dt>
+ <dd>
+ <p><!-- CL 226984 -->
+ <a href="/pkg/encoding/asn1/#Marshal"><code>Marshal</code></a> now sorts the components
+ of SET OF according to X.690 DER.
+ </p>
+
+ <p><!-- CL 227320 -->
+ <a href="/pkg/encoding/asn1/#Unmarshal"><code>Unmarshal</code></a> now rejects tags and
+ Object Identifiers which are not minimally encoded according to X.690 DER.
+ </p>
+ </dd>
+</dl><!-- encoding/asn1 -->
+
+<dl id="encoding/json"><dt><a href="/pkg/encoding/json/">encoding/json</a></dt>
+ <dd>
+ <p><!-- CL 191783 -->
+ Decoding a JSON array into a slice no longer reuses any existing slice elements,
+ following the rules that the package documentation already stated.
+ </p>
+
+ <p><!-- CL 199837 -->
+ The package now has an internal limit to the maximum depth of
+ nesting when decoding. This reduces the possibility that a
+ deeply nested input could use large quantities of stack memory,
+ or even cause a "goroutine stack exceeds limit" panic.
+ </p>
+ </dd>
+</dl><!-- encoding/json -->
<dl id="flag"><dt><a href="/pkg/flag/">flag</a></dt>
<dd>
<p><!-- CL 221427 -->
When the flag package sees <code>-h</code> or <code>-help</code>, and
- those flags are not defined, the flag package prints a usage message.
+ those flags are not defined, it now prints a usage message.
If the <a href="/pkg/flag/#FlagSet"><code>FlagSet</code></a> was created with
<a href="/pkg/flag/#ExitOnError"><code>ExitOnError</code></a>,
<a href="/pkg/flag/#FlagSet.Parse"><code>FlagSet.Parse</code></a> would then
@@ -210,6 +647,46 @@ TODO
</dd>
</dl>
+<dl id="fmt"><dt><a href="/pkg/fmt/">fmt</a></dt>
+ <dd>
+ <p><!-- CL 215001 -->
+ The printing verbs <code>%#g</code> and <code>%#G</code> now preserve
+ trailing zeros for floating-point values.
+ </p>
+ </dd>
+</dl><!-- fmt -->
+
+<dl id="go/printer"><dt><a href="/pkg/go/printer/">go/printer</a></dt>
+ <dd>
+ <p><!-- CL 231461 -->
+ The new <a href="/pkg/go/printer/#Mode"><code>Mode</code></a>
+ value <a href="/pkg/go/printer/#StdFormat"><code>StdFormat</code></a>
+ directs the printer to apply standard formatting changes while
+ printing the output.
+ </dd>
+</dl><!-- go/printer -->
+
+<dl id="io/ioutil"><dt><a href="/pkg/io/ioutil/">io/ioutil</a></dt>
+ <dd>
+ <p><!-- CL 212597 -->
+ <a href="/pkg/io/ioutil/#TempDir"><code>TempDir</code></a> and
+ <a href="/pkg/io/ioutil/#TempFile"><code>TempFile</code></a>
+ now reject patterns that contain path separators.
+ That is, calls such as <code>ioutil.TempFile("/tmp",</code> <code>"../base*")</code> will no longer succeed.
+ This prevents unintended directory traversal.
+ </p>
+ </dd>
+</dl><!-- io/ioutil -->
+
+<dl id="math/big"><dt><a href="/pkg/math/big/">math/big</a></dt>
+ <dd>
+ <p><!-- CL 230397 -->
+ The new <a href="/pkg/math/big/#Int.FillBytes"><code>Int.FillBytes</code></a>
+ method allows serializing to fixed-size pre-allocated byte slices.
+ </p>
+ </dd>
+</dl><!-- math/big -->
+
<dl id="net"><dt><a href="/pkg/net/">net</a></dt>
<dd>
<p><!-- CL 228645 -->
@@ -218,7 +695,7 @@ TODO
<code>Conn.SetReadDeadline</code>,
or <code>Conn.SetWriteDeadline</code> methods, it will now
return an error that is or wraps
- <a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
+ <a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
This may be used to reliably detect whether an error is due to
an exceeded deadline.
Earlier releases recommended calling the <code>Timeout</code>
@@ -234,6 +711,16 @@ TODO
</dd>
</dl>
+<dl id="net/http"><dt><a href="/pkg/net/http/">net/http</a></dt>
+ <dd>
+ <p><!-- CL 231418, CL 231419 -->
+ Parsing is now stricter as a hardening measure against request smuggling attacks:
+ non-ASCII white space is no longer trimmed like SP and HTAB, and support for the
+ "<code>identity</code>" <code>Transfer-Encoding</code> was dropped.
+ </p>
+ </dd>
+</dl><!-- net/http -->
+
<dl id="net/http/httputil"><dt><a href="/pkg/net/http/httputil/">net/http/httputil</a></dt>
<dd>
<p><!-- CL 230937 -->
@@ -242,6 +729,12 @@ TODO
header when the incoming <code>Request.Header</code> map entry
for that field is <code>nil</code>.
</p>
+
+ <p><!-- CL 224897 -->
+ When a Switching Protocol (like WebSocket) request handled by
+ <a href="/pkg/net/http/httputil/#ReverseProxy"><code>ReverseProxy</code></a>
+ is canceled, the backend connection is now correctly closed.
+ </p>
</dd>
</dl>
@@ -281,7 +774,7 @@ TODO
<a href="/pkg/os/#File.SetReadDeadline"><code>File.SetReadDeadline</code></a>,
or <a href="/pkg/os/#File.SetWriteDeadline"><code>File.SetWriteDeadline</code></a>
methods, it will now return an error that is or wraps
- <a href="/pkg/os#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
+ <a href="/pkg/os/#ErrDeadlineExceeded"><code>os.ErrDeadlineExceeded</code></a>.
This may be used to reliably detect whether an error is due to
an exceeded deadline.
Earlier releases recommended calling the <code>Timeout</code>
@@ -289,13 +782,48 @@ TODO
which <code>Timeout</code> returns <code>true</code> although a
deadline has not been exceeded.
</p>
+
+ <p><!-- CL 232862 -->
+ Packages <code>os</code> and <code>net</code> now automatically
+ retry system calls that fail with <code>EINTR</code>. Previously
+ this led to spurious failures, which became more common in Go
+ 1.14 with the addition of asynchronous preemption. Now this is
+ handled transparently.
+ </p>
+
+ <p><!-- CL 229101 -->
+ The <a href="/pkg/os/#File"><code>os.File</code></a> type now
+ supports a <a href="/pkg/os/#File.ReadFrom"><code>ReadFrom</code></a>
+ method. This permits the use of the <code>copy_file_range</code>
+ system call on some systems when using
+ <a href="/pkg/io/#Copy"><code>io.Copy</code></a> to copy data
+ from one <code>os.File</code> to another. A consequence is that
+ <a href="/pkg/io/#CopyBuffer"><code>io.CopyBuffer</code></a>
+ will not always use the provided buffer when copying to a
+ <code>os.File</code>. If a program wants to force the use of
+ the provided buffer, it can be done by writing
+ <code>io.CopyBuffer(struct{ io.Writer }{dst}, src, buf)</code>.
+ </p>
+ </dd>
+</dl>
+
+<dl id="plugin"><dt><a href="/pkg/plugin/">plugin</a></dt>
+ <dd>
+ <p><!-- CL 182959 -->
+ DWARF generation is now supported (and enabled by default) for <code>-buildmode=plugin</code> on macOS.
+ </p>
+ </dd>
+ <dd>
+ <p><!-- CL 191617 -->
+ Building with <code>-buildmode=plugin</code> is now supported on <code>freebsd/amd64</code>.
+ </p>
</dd>
</dl>
<dl id="reflect"><dt><a href="/pkg/reflect/">reflect</a></dt>
<dd>
<p><!-- CL 228902 -->
- Package reflect now disallows accessing methods of all
+ Package <code>reflect</code> now disallows accessing methods of all
non-exported fields, whereas previously it allowed accessing
those of non-exported, embedded fields. Code that relies on the
previous behavior should be updated to instead access the
@@ -304,30 +832,29 @@ TODO
</dd>
</dl>
-<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
+<dl id="regexp"><dt><a href="/pkg/regexp/">regexp</a></dt>
<dd>
- <p><!-- CL 221779 -->
- If <code>panic</code> is invoked with a value whose type is derived from any
- of: <code>bool</code>, <code>complex64</code>, <code>complex128</code>, <code>float32</code>, <code>float64</code>,
- <code>int</code>, <code>int8</code>, <code>int16</code>, <code>int32</code>, <code>int64</code>, <code>string</code>,
- <code>uint</code>, <code>uint8</code>, <code>uint16</code>, <code>uint32</code>, <code>uint64</code>, <code>uintptr</code>,
- then the value will be printed, instead of just its address.
+ <p><!-- CL 187919 -->
+ The new <a href="/pkg/regexp/#Regexp.SubexpIndex"><code>Regexp.SubexpIndex</code></a>
+ method returns the index of the first subexpression with the given name
+ within the regular expression.
</p>
+ </dd>
+</dl><!-- regexp -->
- <p><!-- CL -->
- On a Unix system, if the <code>kill</code> command
- or <code>kill</code> system call is used to send
- a <code>SIGSEGV</code>, <code>SIGBUS</code>,
- or <code>SIGFPE</code> signal to a Go program, and if the signal
- is not being handled via
- <a href="/pkg/os/signal/#Notify"><code>os/signal.Notify</code></a>,
- the Go program will now reliably crash with a stack trace.
- In earlier releases the behavior was unpredictable.
+<dl id="pkg-runtime"><dt><a href="/pkg/runtime/">runtime</a></dt>
+ <dd>
+ <p><!-- CL 216557 -->
+ Several functions, including
+ <a href="/pkg/runtime/#ReadMemStats"><code>ReadMemStats</code></a>
+ and
+ <a href="/pkg/runtime/#GoroutineProfile"><code>GoroutineProfile</code></a>,
+ no longer block if a garbage collection is in progress.
</p>
</dd>
</dl>
-<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof">runtime/pprof</a></dt>
+<dl id="pkg-runtime-pprof"><dt><a href="/pkg/runtime/pprof/">runtime/pprof</a></dt>
<dd>
<p><!-- CL 189318 -->
The goroutine profile includes the profile labels associated with each goroutine
@@ -337,6 +864,20 @@ TODO
</dd>
</dl>
+<dl id="strconv"><dt><a href="/pkg/strconv/">strconv</a></dt>
+ <dd>
+ <p><!-- CL 216617 -->
+ <a href="/pkg/strconv/#FormatComplex"><code>FormatComplex</code></a> and <a href="/pkg/strconv/#ParseComplex"><code>ParseComplex</code></a> are added for working with complex numbers.
+ </p>
+ <p>
+ <a href="/pkg/strconv/#FormatComplex"><code>FormatComplex</code></a> converts a complex number into a string of the form (a+bi), where a and b are the real and imaginary parts.
+ </p>
+ <p>
+ <a href="/pkg/strconv/#ParseComplex"><code>ParseComplex</code></a> converts a string into a complex number of a specified precision. <code>ParseComplex</code> accepts complex numbers in the format <code>N+Ni</code>.
+ </p>
+ </dd>
+</dl><!-- strconv -->
+
<dl id="sync"><dt><a href="/pkg/sync/">sync</a></dt>
<dd>
<p><!-- CL 205899, golang.org/issue/33762 -->
@@ -370,18 +911,42 @@ TODO
Some programs that set <code>Setctty</code> will need to change
the value of <code>Ctty</code> to use a child descriptor number.
</p>
+
+ <p><!-- CL 220578 -->
+ It is <a href="/pkg/syscall/#Proc.Call">now possible</a> to call
+ system calls that return floating point values
+ on <code>windows/amd64</code>.
+ </p>
</dd>
</dl>
<dl id="testing"><dt><a href="/pkg/testing/">testing</a></dt>
<dd>
+ <p><!-- golang.org/issue/28135 -->
+ The <code>testing.T</code> type now has a
+ <a href="/pkg/testing/#T.Deadline"><code>Deadline</code></a> method
+ that reports the time at which the test binary will have exceeded its
+ timeout.
+ </p>
+
+ <p><!-- golang.org/issue/34129 -->
+ A <code>TestMain</code> function is no longer required to call
+ <code>os.Exit</code>. If a <code>TestMain</code> function returns,
+ the test binary will call <code>os.Exit</code> with the value returned
+ by <code>m.Run</code>.
+ </p>
+
<p><!-- CL 226877, golang.org/issue/35998 -->
The new methods
<a href="/pkg/testing/#T.TempDir"><code>T.TempDir</code></a> and
- <a href="/pkg/testing/#B.TempDir"><code>B.TempDir</code></a> and
+ <a href="/pkg/testing/#B.TempDir"><code>B.TempDir</code></a>
return temporary directories that are automatically cleaned up
at the end of the test.
</p>
+
+ <p><!-- CL 229085 -->
+ TODO: <a href="https://golang.org/cl/229085">https://golang.org/cl/229085</a>: reformat test chatty output
+ </p>
</dd>
</dl><!-- testing -->
@@ -392,5 +957,9 @@ TODO
<a href="/pkg/time/#Ticker.Reset"><code>Ticker.Reset</code></a>
supports changing the duration of a ticker.
</p>
+
+ <p><!-- CL 227878 -->
+ When returning an error, <a href="/pkg/time/#ParseDuration"><code>ParseDuration</code></a> now quotes the original value.
+ </p>
</dd>
</dl><!-- time -->
diff --git a/doc/go_faq.html b/doc/go_faq.html
index e40dde77e8..23a3080c9b 100644
--- a/doc/go_faq.html
+++ b/doc/go_faq.html
@@ -515,7 +515,7 @@ when used well, can result in clean error-handling code.
See the <a href="/doc/articles/defer_panic_recover.html">Defer, Panic, and Recover</a> article for details.
Also, the <a href="https://blog.golang.org/errors-are-values">Errors are values</a> blog post
describes one approach to handling errors cleanly in Go by demonstrating that,
-since errors are just values, the full power of Go can deployed in error handling.
+since errors are just values, the full power of Go can be deployed in error handling.
</p>
<h3 id="assertions">
diff --git a/doc/help.html b/doc/help.html
index b305a57763..3d32ae5dc0 100644
--- a/doc/help.html
+++ b/doc/help.html
@@ -8,7 +8,7 @@
<h2 id="help">Get help</h2>
-<img class="gopher" src="/doc/gopher/help.png"/>
+<img class="gopher" src="/doc/gopher/help.png" alt=""/>
{{if not $.GoogleCN}}
<h3 id="mailinglist"><a href="https://groups.google.com/group/golang-nuts">Go Nuts Mailing List</a></h3>
diff --git a/doc/install-source.html b/doc/install-source.html
index 8f0d3a9d14..f8cda1dc21 100644
--- a/doc/install-source.html
+++ b/doc/install-source.html
@@ -33,7 +33,7 @@ compiler using the GCC back end, see
</p>
<p>
-The Go compilers support twelve instruction sets:
+The Go compilers support the following instruction sets:
<dl>
<dt>
@@ -49,22 +49,28 @@ The Go compilers support twelve instruction sets:
The <code>ARM</code> instruction set, 64-bit (<code>AArch64</code>) and 32-bit.
</dd>
<dt>
+ <code>mips64</code>, <code>mips64le</code>, <code>mips</code>, <code>mipsle</code>
+</dt>
+<dd>
+ The <code>MIPS</code> instruction set, big- and little-endian, 64- and 32-bit.
+</dd>
+<dt>
<code>ppc64</code>, <code>ppc64le</code>
</dt>
<dd>
The 64-bit PowerPC instruction set, big- and little-endian.
</dd>
<dt>
- <code>s390x</code>
+ <code>riscv64</code>
</dt>
<dd>
- The IBM z/Architecture.
+ The 64-bit RISC-V instruction set.
</dd>
<dt>
- <code>mips64</code>, <code>mips64le</code>, <code>mips</code>, <code>mipsle</code>
+ <code>s390x</code>
</dt>
<dd>
- The <code>MIPS</code> instruction set, big- and little-endian, 64- and 32-bit.
+ The IBM z/Architecture.
</dd>
<dt>
<code>wasm</code>
@@ -501,7 +507,7 @@ These default to the values of <code>$GOHOSTOS</code> and
<p>
Choices for <code>$GOOS</code> are
-<code>android</code>, <code>darwin</code> (macOS 10.11 and above and iOS),
+<code>android</code>, <code>darwin</code> (macOS/iOS),
<code>dragonfly</code>, <code>freebsd</code>, <code>illumos</code>, <code>js</code>,
<code>linux</code>, <code>netbsd</code>, <code>openbsd</code>,
<code>plan9</code>, <code>solaris</code> and <code>windows</code>.
diff --git a/misc/cgo/test/test.go b/misc/cgo/test/test.go
index b5009d43ce..8c69ad91ac 100644
--- a/misc/cgo/test/test.go
+++ b/misc/cgo/test/test.go
@@ -2200,3 +2200,7 @@ func test32579(t *testing.T) {
// issue 38649
var issue38649 C.netbsd_gid = 42
+
+// issue 39877
+
+var issue39877 *C.void = nil
diff --git a/misc/cgo/test/testdata/issue27054/egl.h b/misc/cgo/test/testdata/issue27054/egl.h
index 33a759ea2a..30796273e8 100644
--- a/misc/cgo/test/testdata/issue27054/egl.h
+++ b/misc/cgo/test/testdata/issue27054/egl.h
@@ -5,3 +5,4 @@
// This is the relevant part of EGL/egl.h.
typedef void *EGLDisplay;
+typedef void *EGLConfig;
diff --git a/misc/cgo/test/testdata/issue27054/test27054.go b/misc/cgo/test/testdata/issue27054/test27054.go
index 186f5bd602..01bf43a913 100644
--- a/misc/cgo/test/testdata/issue27054/test27054.go
+++ b/misc/cgo/test/testdata/issue27054/test27054.go
@@ -13,5 +13,9 @@ import (
)
func Test27054(t *testing.T) {
- var _ C.EGLDisplay = 0 // Note: 0, not nil. That makes sure we use uintptr for this type.
+ var (
+ // Note: 0, not nil. That makes sure we use uintptr for these types.
+ _ C.EGLDisplay = 0
+ _ C.EGLConfig = 0
+ )
}
diff --git a/misc/cgo/testgodefs/testdata/issue39534.go b/misc/cgo/testgodefs/testdata/issue39534.go
new file mode 100644
index 0000000000..9899ba1673
--- /dev/null
+++ b/misc/cgo/testgodefs/testdata/issue39534.go
@@ -0,0 +1,12 @@
+// Copyright 2020 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 ignore
+
+package main
+
+// enum { ENUMVAL = 0x1 };
+import "C"
+
+const ENUMVAL = C.ENUMVAL
diff --git a/misc/cgo/testgodefs/testgodefs_test.go b/misc/cgo/testgodefs/testgodefs_test.go
index 178fff3fbc..e4085f9ca8 100644
--- a/misc/cgo/testgodefs/testgodefs_test.go
+++ b/misc/cgo/testgodefs/testgodefs_test.go
@@ -24,6 +24,7 @@ var filePrefixes = []string{
"issue37479",
"issue37621",
"issue38649",
+ "issue39534",
}
func TestGoDefs(t *testing.T) {
diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go
index ab98f61c0a..2875271c03 100644
--- a/misc/cgo/testplugin/plugin_test.go
+++ b/misc/cgo/testplugin/plugin_test.go
@@ -32,7 +32,7 @@ func TestMain(m *testing.M) {
}
func testMain(m *testing.M) int {
- // Copy testdata into GOPATH/src/testarchive, along with a go.mod file
+ // Copy testdata into GOPATH/src/testplugin, along with a go.mod file
// declaring the same path.
GOPATH, err := ioutil.TempDir("", "plugin_test")
diff --git a/misc/cgo/testshared/shared_test.go b/misc/cgo/testshared/shared_test.go
index acae1b2c21..f8dabbe7a0 100644
--- a/misc/cgo/testshared/shared_test.go
+++ b/misc/cgo/testshared/shared_test.go
@@ -38,7 +38,15 @@ var testWork = flag.Bool("testwork", false, "if true, log and do not delete the
// run runs a command and calls t.Errorf if it fails.
func run(t *testing.T, msg string, args ...string) {
+ runWithEnv(t, msg, nil, args...)
+}
+
+// runWithEnv runs a command under the given environment and calls t.Errorf if it fails.
+func runWithEnv(t *testing.T, msg string, env []string, args ...string) {
c := exec.Command(args[0], args[1:]...)
+ if len(env) != 0 {
+ c.Env = append(os.Environ(), env...)
+ }
if output, err := c.CombinedOutput(); err != nil {
t.Errorf("executing %s (%s) failed %s:\n%s", strings.Join(args, " "), msg, err, output)
}
@@ -1028,3 +1036,17 @@ func TestGeneratedHash(t *testing.T) {
goCmd(nil, "install", "-buildmode=shared", "-linkshared", "./issue30768/issue30768lib")
goCmd(nil, "test", "-linkshared", "./issue30768")
}
+
+// Test that packages can be added not in dependency order (here a depends on b, and a adds
+// before b). This could happen with e.g. go build -buildmode=shared std. See issue 39777.
+func TestPackageOrder(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./issue39777/a", "./issue39777/b")
+}
+
+// Test that GC data are generated correctly by the linker when it needs a type defined in
+// a shared library. See issue 39927.
+func TestGCData(t *testing.T) {
+ goCmd(t, "install", "-buildmode=shared", "-linkshared", "./gcdata/p")
+ goCmd(t, "build", "-linkshared", "./gcdata/main")
+ runWithEnv(t, "running gcdata/main", []string{"GODEBUG=clobberfree=1"}, "./main")
+}
diff --git a/misc/cgo/testshared/testdata/gcdata/main/main.go b/misc/cgo/testshared/testdata/gcdata/main/main.go
new file mode 100644
index 0000000000..394862fd94
--- /dev/null
+++ b/misc/cgo/testshared/testdata/gcdata/main/main.go
@@ -0,0 +1,37 @@
+// Copyright 2020 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 GC data is generated correctly for global
+// variables with types defined in a shared library.
+// See issue 39927.
+
+// This test run under GODEBUG=clobberfree=1. The check
+// *x[i] == 12345 depends on this debug mode to clobber
+// the value if the object is freed prematurely.
+
+package main
+
+import (
+ "fmt"
+ "runtime"
+ "testshared/gcdata/p"
+)
+
+var x p.T
+
+func main() {
+ for i := range x {
+ x[i] = new(int)
+ *x[i] = 12345
+ }
+ runtime.GC()
+ runtime.GC()
+ runtime.GC()
+ for i := range x {
+ if *x[i] != 12345 {
+ fmt.Printf("x[%d] == %d, want 12345\n", i, *x[i])
+ panic("FAIL")
+ }
+ }
+}
diff --git a/misc/cgo/testshared/testdata/gcdata/p/p.go b/misc/cgo/testshared/testdata/gcdata/p/p.go
new file mode 100644
index 0000000000..1fee75429e
--- /dev/null
+++ b/misc/cgo/testshared/testdata/gcdata/p/p.go
@@ -0,0 +1,7 @@
+// Copyright 2020 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 T [10]*int
diff --git a/misc/cgo/testshared/testdata/issue39777/a/a.go b/misc/cgo/testshared/testdata/issue39777/a/a.go
new file mode 100644
index 0000000000..c7bf835951
--- /dev/null
+++ b/misc/cgo/testshared/testdata/issue39777/a/a.go
@@ -0,0 +1,9 @@
+// Copyright 2020 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 a
+
+import "testshared/issue39777/b"
+
+func F() { b.F() }
diff --git a/misc/cgo/testshared/testdata/issue39777/b/b.go b/misc/cgo/testshared/testdata/issue39777/b/b.go
new file mode 100644
index 0000000000..4e681965e6
--- /dev/null
+++ b/misc/cgo/testshared/testdata/issue39777/b/b.go
@@ -0,0 +1,7 @@
+// Copyright 2020 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 b
+
+func F() {}
diff --git a/misc/wasm/wasm_exec.js b/misc/wasm/wasm_exec.js
index a99aaeda07..8501ae7cd8 100644
--- a/misc/wasm/wasm_exec.js
+++ b/misc/wasm/wasm_exec.js
@@ -175,37 +175,19 @@
const storeValue = (addr, v) => {
const nanHead = 0x7FF80000;
- if (typeof v === "number") {
+ if (typeof v === "number" && v !== 0) {
if (isNaN(v)) {
this.mem.setUint32(addr + 4, nanHead, true);
this.mem.setUint32(addr, 0, true);
return;
}
- if (v === 0) {
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 1, true);
- return;
- }
this.mem.setFloat64(addr, v, true);
return;
}
- switch (v) {
- case undefined:
- this.mem.setFloat64(addr, 0, true);
- return;
- case null:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 2, true);
- return;
- case true:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 3, true);
- return;
- case false:
- this.mem.setUint32(addr + 4, nanHead, true);
- this.mem.setUint32(addr, 4, true);
- return;
+ if (v === undefined) {
+ this.mem.setFloat64(addr, 0, true);
+ return;
}
let id = this._ids.get(v);
@@ -219,8 +201,13 @@
this._ids.set(v, id);
}
this._goRefCounts[id]++;
- let typeFlag = 1;
+ let typeFlag = 0;
switch (typeof v) {
+ case "object":
+ if (v !== null) {
+ typeFlag = 1;
+ }
+ break;
case "string":
typeFlag = 2;
break;
@@ -493,10 +480,17 @@
global,
this,
];
- this._goRefCounts = []; // number of references that Go has to a JS value, indexed by reference id
- this._ids = new Map(); // mapping from JS values to reference ids
- this._idPool = []; // unused ids that have been garbage collected
- this.exited = false; // whether the Go program has exited
+ this._goRefCounts = new Array(this._values.length).fill(Infinity); // number of references that Go has to a JS value, indexed by reference id
+ this._ids = new Map([ // mapping from JS values to reference ids
+ [0, 1],
+ [null, 2],
+ [true, 3],
+ [false, 4],
+ [global, 5],
+ [this, 6],
+ ]);
+ this._idPool = []; // unused ids that have been garbage collected
+ this.exited = false; // whether the Go program has exited
// Pass command line arguments and environment variables to WebAssembly by writing them to the linear memory.
let offset = 4096;
diff --git a/src/all.bat b/src/all.bat
index 8bbd6b1b5d..ae835d992f 100644
--- a/src/all.bat
+++ b/src/all.bat
@@ -1,27 +1,27 @@
-:: 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.
-
-@echo off
-
-setlocal
-
-if exist make.bat goto ok
-echo all.bat must be run from go\src
-:: cannot exit: would kill parent command interpreter
-goto end
-:ok
-
-set OLDPATH=%PATH%
-call make.bat --no-banner --no-local
-if %GOBUILDFAIL%==1 goto end
-call run.bat --no-rebuild --no-local
-if %GOBUILDFAIL%==1 goto end
-:: we must restore %PATH% before running "dist banner" so that the latter
-:: can get the original %PATH% and give suggestion to add %GOROOT%/bin
-:: to %PATH% if necessary.
-set PATH=%OLDPATH%
-"%GOTOOLDIR%/dist" banner
-
-:end
-if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
+:: 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.
+
+@echo off
+
+setlocal
+
+if exist make.bat goto ok
+echo all.bat must be run from go\src
+:: cannot exit: would kill parent command interpreter
+goto end
+:ok
+
+set OLDPATH=%PATH%
+call make.bat --no-banner --no-local
+if %GOBUILDFAIL%==1 goto end
+call run.bat --no-rebuild --no-local
+if %GOBUILDFAIL%==1 goto end
+:: we must restore %PATH% before running "dist banner" so that the latter
+:: can get the original %PATH% and give suggestion to add %GOROOT%/bin
+:: to %PATH% if necessary.
+set PATH=%OLDPATH%
+"%GOTOOLDIR%/dist" banner
+
+:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/bufio/scan_test.go b/src/bufio/scan_test.go
index ceb813ae8d..e99b09f66f 100644
--- a/src/bufio/scan_test.go
+++ b/src/bufio/scan_test.go
@@ -558,8 +558,8 @@ func (r *negativeEOFReader) Read(p []byte) (int, error) {
return -1, io.EOF
}
-// Test that the scanner doesn't panic on a reader that returns a
-// negative count of bytes read (issue 38053).
+// Test that the scanner doesn't panic and returns ErrBadReadCount
+// on a reader that returns a negative count of bytes read (issue 38053).
func TestNegativeEOFReader(t *testing.T) {
r := negativeEOFReader(10)
scanner := NewScanner(&r)
@@ -571,8 +571,8 @@ func TestNegativeEOFReader(t *testing.T) {
break
}
}
- if scanner.Err() == nil {
- t.Error("scanner.Err returned nil, expected an error")
+ if got, want := scanner.Err(), ErrBadReadCount; got != want {
+ t.Errorf("scanner.Err: got %v, want %v", got, want)
}
}
@@ -584,11 +584,13 @@ func (largeReader) Read(p []byte) (int, error) {
return len(p) + 1, nil
}
+// Test that the scanner doesn't panic and returns ErrBadReadCount
+// on a reader that returns an impossibly large count of bytes read (issue 38053).
func TestLargeReader(t *testing.T) {
scanner := NewScanner(largeReader{})
for scanner.Scan() {
}
- if scanner.Err() == nil {
- t.Error("scanner.Err returned nil, expected an error")
+ if got, want := scanner.Err(), ErrBadReadCount; got != want {
+ t.Errorf("scanner.Err: got %v, want %v", got, want)
}
}
diff --git a/src/clean.bat b/src/clean.bat
index 0954dcd67f..c957353d0f 100644
--- a/src/clean.bat
+++ b/src/clean.bat
@@ -1,32 +1,32 @@
-:: 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.
-
-@echo off
-
-setlocal
-
-set GOBUILDFAIL=0
-
-go tool dist env -w -p >env.bat
-if errorlevel 1 goto fail
-call env.bat
-del env.bat
-echo.
-
-if exist %GOTOOLDIR%\dist.exe goto distok
-echo cannot find %GOTOOLDIR%\dist; nothing to clean
-goto fail
-:distok
-
-"%GOBIN%\go" clean -i std
-"%GOBIN%\go" tool dist clean
-"%GOBIN%\go" clean -i cmd
-
-goto end
-
-:fail
-set GOBUILDFAIL=1
-
-:end
-if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
+:: 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.
+
+@echo off
+
+setlocal
+
+set GOBUILDFAIL=0
+
+go tool dist env -w -p >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
+if exist %GOTOOLDIR%\dist.exe goto distok
+echo cannot find %GOTOOLDIR%\dist; nothing to clean
+goto fail
+:distok
+
+"%GOBIN%\go" clean -i std
+"%GOBIN%\go" tool dist clean
+"%GOBIN%\go" clean -i cmd
+
+goto end
+
+:fail
+set GOBUILDFAIL=1
+
+:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/cmd/addr2line/addr2line_test.go b/src/cmd/addr2line/addr2line_test.go
index 22bf1379bb..578d88e432 100644
--- a/src/cmd/addr2line/addr2line_test.go
+++ b/src/cmd/addr2line/addr2line_test.go
@@ -73,19 +73,29 @@ func testAddr2Line(t *testing.T, exepath, addr string) {
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
+ // Debug paths are stored slash-separated, so convert to system-native.
+ srcPath = filepath.FromSlash(srcPath)
fi2, err := os.Stat(srcPath)
+ if gorootFinal := os.Getenv("GOROOT_FINAL"); gorootFinal != "" && strings.HasPrefix(srcPath, gorootFinal) {
+ if os.IsNotExist(err) || (err == nil && !os.SameFile(fi1, fi2)) {
+ // srcPath has had GOROOT_FINAL substituted for GOROOT, and it doesn't
+ // match the actual file. GOROOT probably hasn't been moved to its final
+ // location yet, so try the original location instead.
+ fi2, err = os.Stat(runtime.GOROOT() + strings.TrimPrefix(srcPath, gorootFinal))
+ }
+ }
if err != nil {
t.Fatalf("Stat failed: %v", err)
}
if !os.SameFile(fi1, fi2) {
t.Fatalf("addr2line_test.go and %s are not same file", srcPath)
}
- if srcLineNo != "89" {
- t.Fatalf("line number = %v; want 89", srcLineNo)
+ if srcLineNo != "99" {
+ t.Fatalf("line number = %v; want 99", srcLineNo)
}
}
-// This is line 88. The test depends on that.
+// This is line 98. The test depends on that.
func TestAddr2Line(t *testing.T) {
testenv.MustHaveGoBuild(t)
diff --git a/src/cmd/asm/doc.go b/src/cmd/asm/doc.go
index 8bf0acac25..4a0c785aad 100644
--- a/src/cmd/asm/doc.go
+++ b/src/cmd/asm/doc.go
@@ -33,14 +33,17 @@ Flags:
Dump instructions as they are parsed.
-dynlink
Support references to Go symbols defined in other shared libraries.
+ -gensymabis
+ Write symbol ABI information to output file. Don't assemble.
-o file
Write output to file. The default is foo.o for /a/b/c/foo.s.
-shared
Generate code that can be linked into a shared library.
+ -spectre list
+ Enable spectre mitigations in list (all, ret).
-trimpath prefix
Remove prefix from recorded source file paths.
- -gensymabis
- Write symbol ABI information to output file. Don't assemble.
+
Input language:
The assembler uses mostly the same syntax for all architectures,
diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s
index c0e2fb7e0e..69267bfa63 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64.s
@@ -274,6 +274,9 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8
ADDW $0x60060, R2 // ADDW $393312, R2 // 4280011142804111
CMPW $0x60060, R2 // CMPW $393312, R2 // 1b0c8052db00a0725f001b6b
+ // TODO: this could have better encoding
+ ANDW $-1, R10 // 1b0080124a011b0a
+
AND $8, R0, RSP // 1f007d92
ORR $8, R0, RSP // 1f007db2
EOR $8, R0, RSP // 1f007dd2
diff --git a/src/cmd/asm/internal/asm/testdata/arm64enc.s b/src/cmd/asm/internal/asm/testdata/arm64enc.s
index a483c731b8..56cf51c303 100644
--- a/src/cmd/asm/internal/asm/testdata/arm64enc.s
+++ b/src/cmd/asm/internal/asm/testdata/arm64enc.s
@@ -420,6 +420,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$-8
UXTBW R2, R6 // 461c0053
UXTHW R7, R20 // f43c0053
VCNT V0.B8, V0.B8 // 0058200e
+ VCNT V0.B16, V0.B16 // 0058204e
WFE // 5f2003d5
WFI // 7f2003d5
YIELD // 3f2003d5
diff --git a/src/cmd/cgo/doc.go b/src/cmd/cgo/doc.go
index 8c3bf81bf7..ca18c45d9d 100644
--- a/src/cmd/cgo/doc.go
+++ b/src/cmd/cgo/doc.go
@@ -413,7 +413,7 @@ type in Go are instead represented by a uintptr. Those include:
jobjectArray
jweak
-3. The EGLDisplay type from the EGL API.
+3. The EGLDisplay and EGLConfig types from the EGL API.
These types are uintptr on the Go side because they would otherwise
confuse the Go garbage collector; they are sometimes not really
@@ -429,11 +429,16 @@ from Go 1.9 and earlier, use the cftype or jni rewrites in the Go fix tool:
It will replace nil with 0 in the appropriate places.
-The EGLDisplay case were introduced in Go 1.12. Use the egl rewrite
+The EGLDisplay case was introduced in Go 1.12. Use the egl rewrite
to auto-update code from Go 1.11 and earlier:
go tool fix -r egl <pkg>
+The EGLConfig case was introduced in Go 1.15. Use the eglconf rewrite
+to auto-update code from Go 1.14 and earlier:
+
+ go tool fix -r eglconf <pkg>
+
Using cgo directly
Usage:
@@ -985,7 +990,7 @@ produces a file named a.out, even if cmd/link does so by invoking the host
linker in external linking mode.
By default, cmd/link will decide the linking mode as follows: if the only
-packages using cgo are those on a whitelist of standard library
+packages using cgo are those on a list of known standard library
packages (net, os/user, runtime/cgo), cmd/link will use internal linking
mode. Otherwise, there are non-standard cgo packages involved, and cmd/link
will use external linking mode. The first rule means that a build of
diff --git a/src/cmd/cgo/gcc.go b/src/cmd/cgo/gcc.go
index edcbd8d2d1..a59534ebd0 100644
--- a/src/cmd/cgo/gcc.go
+++ b/src/cmd/cgo/gcc.go
@@ -1354,7 +1354,7 @@ func (p *Package) rewriteRef(f *File) {
if *godefs {
// Substitute definition for mangled type name.
- if r.Name.Type != nil {
+ if r.Name.Type != nil && r.Name.Kind == "type" {
expr = r.Name.Type.Go
}
if id, ok := expr.(*ast.Ident); ok {
@@ -3029,7 +3029,7 @@ func (c *typeConv) badPointerTypedef(dt *dwarf.TypedefType) bool {
if c.badJNI(dt) {
return true
}
- if c.badEGLDisplay(dt) {
+ if c.badEGLType(dt) {
return true
}
return false
@@ -3168,11 +3168,11 @@ func (c *typeConv) badJNI(dt *dwarf.TypedefType) bool {
return false
}
-func (c *typeConv) badEGLDisplay(dt *dwarf.TypedefType) bool {
- if dt.Name != "EGLDisplay" {
+func (c *typeConv) badEGLType(dt *dwarf.TypedefType) bool {
+ if dt.Name != "EGLDisplay" && dt.Name != "EGLConfig" {
return false
}
- // Check that the typedef is "typedef void *EGLDisplay".
+ // Check that the typedef is "typedef void *<name>".
if ptr, ok := dt.Type.(*dwarf.PtrType); ok {
if _, ok := ptr.Type.(*dwarf.VoidType); ok {
return true
diff --git a/src/cmd/cgo/out.go b/src/cmd/cgo/out.go
index 6b40a255d5..6c221473e0 100644
--- a/src/cmd/cgo/out.go
+++ b/src/cmd/cgo/out.go
@@ -98,6 +98,11 @@ func (p *Package) writeDefs() {
typedefNames := make([]string, 0, len(typedef))
for name := range typedef {
+ if name == "_Ctype_void" {
+ // We provide an appropriate declaration for
+ // _Ctype_void below (#39877).
+ continue
+ }
typedefNames = append(typedefNames, name)
}
sort.Strings(typedefNames)
diff --git a/src/cmd/compile/doc.go b/src/cmd/compile/doc.go
index 36dd4bb5cd..46d4722086 100644
--- a/src/cmd/compile/doc.go
+++ b/src/cmd/compile/doc.go
@@ -107,6 +107,8 @@ Flags:
Warn about composite literals that can be simplified.
-shared
Generate code that can be linked into a shared library.
+ -spectre list
+ Enable spectre mitigations in list (all, index, ret).
-traceprofile file
Write an execution trace to file.
-trimpath prefix
diff --git a/src/cmd/compile/fmt_test.go b/src/cmd/compile/fmt_test.go
index f1af6473c7..e372259c78 100644
--- a/src/cmd/compile/fmt_test.go
+++ b/src/cmd/compile/fmt_test.go
@@ -96,7 +96,7 @@ func TestFormats(t *testing.T) {
}
importPath := filepath.Join("cmd/compile", path)
- if blacklistedPackages[filepath.ToSlash(importPath)] {
+ if ignoredPackages[filepath.ToSlash(importPath)] {
return filepath.SkipDir
}
@@ -344,8 +344,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
for index, file := range files {
ast.Inspect(file, func(n ast.Node) bool {
if call, ok := n.(*ast.CallExpr); ok {
- // ignore blacklisted functions
- if blacklistedFunctions[nodeString(call.Fun)] {
+ if ignoredFunctions[nodeString(call.Fun)] {
return true
}
// look for an arguments that might be a format string
@@ -354,7 +353,7 @@ func collectPkgFormats(t *testing.T, pkg *build.Package) {
// make sure we have enough arguments
n := numFormatArgs(s)
if i+1+n > len(call.Args) {
- t.Errorf("%s: not enough format args (blacklist %s?)", posString(call), nodeString(call.Fun))
+ t.Errorf("%s: not enough format args (ignore %s?)", posString(call), nodeString(call.Fun))
break // ignore this call
}
// assume last n arguments are to be formatted;
@@ -549,14 +548,14 @@ func formatReplace(in string, f func(i int, s string) string) string {
return string(append(buf, in[i0:]...))
}
-// blacklistedPackages is the set of packages which can
+// ignoredPackages is the set of packages which can
// be ignored.
-var blacklistedPackages = map[string]bool{}
+var ignoredPackages = map[string]bool{}
-// blacklistedFunctions is the set of functions which may have
+// ignoredFunctions is the set of functions which may have
// format-like arguments but which don't do any formatting and
// thus may be ignored.
-var blacklistedFunctions = map[string]bool{}
+var ignoredFunctions = map[string]bool{}
func init() {
// verify that knownFormats entries are correctly formatted
diff --git a/src/cmd/compile/fmtmap_test.go b/src/cmd/compile/fmtmap_test.go
index 5a24296c5e..179c60187f 100644
--- a/src/cmd/compile/fmtmap_test.go
+++ b/src/cmd/compile/fmtmap_test.go
@@ -115,6 +115,7 @@ var knownFormats = map[string]string{
"cmd/compile/internal/ssa.Sym %v": "",
"cmd/compile/internal/ssa.ValAndOff %s": "",
"cmd/compile/internal/ssa.domain %v": "",
+ "cmd/compile/internal/ssa.flagConstant %s": "",
"cmd/compile/internal/ssa.posetNode %v": "",
"cmd/compile/internal/ssa.posetTestOp %v": "",
"cmd/compile/internal/ssa.rbrank %d": "",
@@ -140,6 +141,7 @@ var knownFormats = map[string]string{
"float64 %.3f": "",
"float64 %.6g": "",
"float64 %g": "",
+ "int %#x": "",
"int %-12d": "",
"int %-6d": "",
"int %-8o": "",
@@ -151,9 +153,11 @@ var knownFormats = map[string]string{
"int %x": "",
"int16 %d": "",
"int16 %x": "",
+ "int32 %#x": "",
"int32 %d": "",
"int32 %v": "",
"int32 %x": "",
+ "int64 %#x": "",
"int64 %+d": "",
"int64 %-10d": "",
"int64 %.5d": "",
@@ -201,6 +205,7 @@ var knownFormats = map[string]string{
"uint64 %b": "",
"uint64 %d": "",
"uint64 %x": "",
+ "uint8 %#x": "",
"uint8 %d": "",
"uint8 %v": "",
"uint8 %x": "",
diff --git a/src/cmd/compile/internal/amd64/ssa.go b/src/cmd/compile/internal/amd64/ssa.go
index b58696d650..47cb422ab1 100644
--- a/src/cmd/compile/internal/amd64/ssa.go
+++ b/src/cmd/compile/internal/amd64/ssa.go
@@ -1252,11 +1252,11 @@ var blockJump = [...]struct {
ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
}
-var eqfJumps = [2][2]gc.FloatingEQNEJump{
+var eqfJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
}
-var nefJumps = [2][2]gc.FloatingEQNEJump{
+var nefJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
}
@@ -1296,10 +1296,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Sym = b.Aux.(*obj.LSym)
case ssa.BlockAMD64EQF:
- s.FPJump(b, next, &eqfJumps)
+ s.CombJump(b, next, &eqfJumps)
case ssa.BlockAMD64NEF:
- s.FPJump(b, next, &nefJumps)
+ s.CombJump(b, next, &nefJumps)
case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
ssa.BlockAMD64LT, ssa.BlockAMD64GE,
diff --git a/src/cmd/compile/internal/arm/ssa.go b/src/cmd/compile/internal/arm/ssa.go
index 9935616f41..765a771546 100644
--- a/src/cmd/compile/internal/arm/ssa.go
+++ b/src/cmd/compile/internal/arm/ssa.go
@@ -857,12 +857,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(obj.AGETCALLERPC)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
- case ssa.OpARMFlagEQ,
- ssa.OpARMFlagLT_ULT,
- ssa.OpARMFlagLT_UGT,
- ssa.OpARMFlagGT_ULT,
- ssa.OpARMFlagGT_UGT:
- v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
+ case ssa.OpARMFlagConstant:
+ v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
case ssa.OpARMInvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
case ssa.OpClobber:
@@ -888,16 +884,30 @@ var condBits = map[ssa.Op]uint8{
var blockJump = map[ssa.BlockKind]struct {
asm, invasm obj.As
}{
- ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
- ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
- ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
- ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
- ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
- ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
- ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
- ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
- ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
- ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
+ ssa.BlockARMEQ: {arm.ABEQ, arm.ABNE},
+ ssa.BlockARMNE: {arm.ABNE, arm.ABEQ},
+ ssa.BlockARMLT: {arm.ABLT, arm.ABGE},
+ ssa.BlockARMGE: {arm.ABGE, arm.ABLT},
+ ssa.BlockARMLE: {arm.ABLE, arm.ABGT},
+ ssa.BlockARMGT: {arm.ABGT, arm.ABLE},
+ ssa.BlockARMULT: {arm.ABLO, arm.ABHS},
+ ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
+ ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
+ ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
+ ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL},
+ ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI},
+}
+
+// To model a 'LEnoov' ('<=' without overflow checking) branching
+var leJumps = [2][2]gc.IndexJump{
+ {{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0]
+ {{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1]
+}
+
+// To model a 'GTnoov' ('>' without overflow checking) branching
+var gtJumps = [2][2]gc.IndexJump{
+ {{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0]
+ {{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1]
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
@@ -941,7 +951,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
ssa.BlockARMLT, ssa.BlockARMGE,
ssa.BlockARMLE, ssa.BlockARMGT,
ssa.BlockARMULT, ssa.BlockARMUGT,
- ssa.BlockARMULE, ssa.BlockARMUGE:
+ ssa.BlockARMULE, ssa.BlockARMUGE,
+ ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
jmp := blockJump[b.Kind]
switch next {
case b.Succs[0].Block():
@@ -958,6 +969,12 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
}
}
+ case ssa.BlockARMLEnoov:
+ s.CombJump(b, next, &leJumps)
+
+ case ssa.BlockARMGTnoov:
+ s.CombJump(b, next, &gtJumps)
+
default:
b.Fatalf("branch not implemented: %s", b.LongString())
}
diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go
index 06c520d76a..b6bb81a847 100644
--- a/src/cmd/compile/internal/arm64/ssa.go
+++ b/src/cmd/compile/internal/arm64/ssa.go
@@ -943,12 +943,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := s.Prog(obj.AGETCALLERPC)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
- case ssa.OpARM64FlagEQ,
- ssa.OpARM64FlagLT_ULT,
- ssa.OpARM64FlagLT_UGT,
- ssa.OpARM64FlagGT_ULT,
- ssa.OpARM64FlagGT_UGT:
- v.Fatalf("Flag* ops should never make it to codegen %v", v.LongString())
+ case ssa.OpARM64FlagConstant:
+ v.Fatalf("FlagConstant op should never make it to codegen %v", v.LongString())
case ssa.OpARM64InvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v.LongString())
case ssa.OpClobber:
@@ -978,26 +974,40 @@ var condBits = map[ssa.Op]int16{
var blockJump = map[ssa.BlockKind]struct {
asm, invasm obj.As
}{
- ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
- ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
- ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
- ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
- ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
- ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
- ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
- ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
- ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
- ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
- ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
- ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
- ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
- ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
- ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
- ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
- ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
- ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
- ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
- ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
+ ssa.BlockARM64EQ: {arm64.ABEQ, arm64.ABNE},
+ ssa.BlockARM64NE: {arm64.ABNE, arm64.ABEQ},
+ ssa.BlockARM64LT: {arm64.ABLT, arm64.ABGE},
+ ssa.BlockARM64GE: {arm64.ABGE, arm64.ABLT},
+ ssa.BlockARM64LE: {arm64.ABLE, arm64.ABGT},
+ ssa.BlockARM64GT: {arm64.ABGT, arm64.ABLE},
+ ssa.BlockARM64ULT: {arm64.ABLO, arm64.ABHS},
+ ssa.BlockARM64UGE: {arm64.ABHS, arm64.ABLO},
+ ssa.BlockARM64UGT: {arm64.ABHI, arm64.ABLS},
+ ssa.BlockARM64ULE: {arm64.ABLS, arm64.ABHI},
+ ssa.BlockARM64Z: {arm64.ACBZ, arm64.ACBNZ},
+ ssa.BlockARM64NZ: {arm64.ACBNZ, arm64.ACBZ},
+ ssa.BlockARM64ZW: {arm64.ACBZW, arm64.ACBNZW},
+ ssa.BlockARM64NZW: {arm64.ACBNZW, arm64.ACBZW},
+ ssa.BlockARM64TBZ: {arm64.ATBZ, arm64.ATBNZ},
+ ssa.BlockARM64TBNZ: {arm64.ATBNZ, arm64.ATBZ},
+ ssa.BlockARM64FLT: {arm64.ABMI, arm64.ABPL},
+ ssa.BlockARM64FGE: {arm64.ABGE, arm64.ABLT},
+ ssa.BlockARM64FLE: {arm64.ABLS, arm64.ABHI},
+ ssa.BlockARM64FGT: {arm64.ABGT, arm64.ABLE},
+ ssa.BlockARM64LTnoov: {arm64.ABMI, arm64.ABPL},
+ ssa.BlockARM64GEnoov: {arm64.ABPL, arm64.ABMI},
+}
+
+// To model a 'LEnoov' ('<=' without overflow checking) branching
+var leJumps = [2][2]gc.IndexJump{
+ {{Jump: arm64.ABEQ, Index: 0}, {Jump: arm64.ABPL, Index: 1}}, // next == b.Succs[0]
+ {{Jump: arm64.ABMI, Index: 0}, {Jump: arm64.ABEQ, Index: 0}}, // next == b.Succs[1]
+}
+
+// To model a 'GTnoov' ('>' without overflow checking) branching
+var gtJumps = [2][2]gc.IndexJump{
+ {{Jump: arm64.ABMI, Index: 1}, {Jump: arm64.ABEQ, Index: 1}}, // next == b.Succs[0]
+ {{Jump: arm64.ABEQ, Index: 1}, {Jump: arm64.ABPL, Index: 0}}, // next == b.Succs[1]
}
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
@@ -1045,7 +1055,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
ssa.BlockARM64Z, ssa.BlockARM64NZ,
ssa.BlockARM64ZW, ssa.BlockARM64NZW,
ssa.BlockARM64FLT, ssa.BlockARM64FGE,
- ssa.BlockARM64FLE, ssa.BlockARM64FGT:
+ ssa.BlockARM64FLE, ssa.BlockARM64FGT,
+ ssa.BlockARM64LTnoov, ssa.BlockARM64GEnoov:
jmp := blockJump[b.Kind]
var p *obj.Prog
switch next {
@@ -1087,6 +1098,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.From.Type = obj.TYPE_CONST
p.Reg = b.Controls[0].Reg()
+ case ssa.BlockARM64LEnoov:
+ s.CombJump(b, next, &leJumps)
+ case ssa.BlockARM64GTnoov:
+ s.CombJump(b, next, &gtJumps)
default:
b.Fatalf("branch not implemented: %s", b.LongString())
}
diff --git a/src/cmd/compile/internal/gc/alg.go b/src/cmd/compile/internal/gc/alg.go
index 835e7e73ba..e2e2374717 100644
--- a/src/cmd/compile/internal/gc/alg.go
+++ b/src/cmd/compile/internal/gc/alg.go
@@ -63,6 +63,26 @@ func IncomparableField(t *types.Type) *types.Field {
return nil
}
+// EqCanPanic reports whether == on type t could panic (has an interface somewhere).
+// t must be comparable.
+func EqCanPanic(t *types.Type) bool {
+ switch t.Etype {
+ default:
+ return false
+ case TINTER:
+ return true
+ case TARRAY:
+ return EqCanPanic(t.Elem())
+ case TSTRUCT:
+ for _, f := range t.FieldSlice() {
+ if !f.Sym.IsBlank() && EqCanPanic(f.Type) {
+ return true
+ }
+ }
+ return false
+ }
+}
+
// algtype is like algtype1, except it returns the fixed-width AMEMxx variants
// instead of the general AMEM kind when possible.
func algtype(t *types.Type) AlgKind {
@@ -591,24 +611,6 @@ func geneq(t *types.Type) *obj.LSym {
}
switch t.Elem().Etype {
- case TINTER:
- // Do two loops. First, check that all the types match (cheap).
- // Second, check that all the data match (expensive).
- // TODO: when the array size is small, unroll the tab match checks.
- checkAll(3, func(pi, qi *Node) *Node {
- // Compare types.
- pi = typecheck(pi, ctxExpr)
- qi = typecheck(qi, ctxExpr)
- eqtab, _ := eqinterface(pi, qi)
- return eqtab
- })
- checkAll(1, func(pi, qi *Node) *Node {
- // Compare data.
- pi = typecheck(pi, ctxExpr)
- qi = typecheck(qi, ctxExpr)
- _, eqdata := eqinterface(pi, qi)
- return eqdata
- })
case TSTRING:
// Do two loops. First, check that all the lengths match (cheap).
// Second, check that all the contents match (expensive).
@@ -642,14 +644,19 @@ func geneq(t *types.Type) *obj.LSym {
case TSTRUCT:
// Build a list of conditions to satisfy.
- // Track their order so that we can preserve aspects of that order.
+ // The conditions are a list-of-lists. Conditions are reorderable
+ // within each inner list. The outer lists must be evaluated in order.
+ // Even within each inner list, track their order so that we can preserve
+ // aspects of that order. (TODO: latter part needed?)
type nodeIdx struct {
n *Node
idx int
}
- var conds []nodeIdx
+ var conds [][]nodeIdx
+ conds = append(conds, []nodeIdx{})
and := func(n *Node) {
- conds = append(conds, nodeIdx{n: n, idx: len(conds)})
+ i := len(conds) - 1
+ conds[i] = append(conds[i], nodeIdx{n: n, idx: len(conds[i])})
}
// Walk the struct using memequal for runs of AMEM
@@ -665,6 +672,10 @@ func geneq(t *types.Type) *obj.LSym {
// Compare non-memory fields with field equality.
if !IsRegularMemory(f.Type) {
+ if EqCanPanic(f.Type) {
+ // Enforce ordering by starting a new set of reorderable conditions.
+ conds = append(conds, []nodeIdx{})
+ }
p := nodSym(OXDOT, np, f.Sym)
q := nodSym(OXDOT, nq, f.Sym)
switch {
@@ -672,17 +683,13 @@ func geneq(t *types.Type) *obj.LSym {
eqlen, eqmem := eqstring(p, q)
and(eqlen)
and(eqmem)
- case f.Type.IsInterface():
- p.Type = f.Type
- p = typecheck(p, ctxExpr)
- q.Type = f.Type
- q = typecheck(q, ctxExpr)
- eqtab, eqdata := eqinterface(p, q)
- and(eqtab)
- and(eqdata)
default:
and(nod(OEQ, p, q))
}
+ if EqCanPanic(f.Type) {
+ // Also enforce ordering after something that can panic.
+ conds = append(conds, []nodeIdx{})
+ }
i++
continue
}
@@ -706,20 +713,24 @@ func geneq(t *types.Type) *obj.LSym {
// Sort conditions to put runtime calls last.
// Preserve the rest of the ordering.
- sort.SliceStable(conds, func(i, j int) bool {
- x, y := conds[i], conds[j]
- if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
- return x.idx < y.idx
- }
- return x.n.Op != OCALL
- })
+ var flatConds []nodeIdx
+ for _, c := range conds {
+ sort.SliceStable(c, func(i, j int) bool {
+ x, y := c[i], c[j]
+ if (x.n.Op != OCALL) == (y.n.Op != OCALL) {
+ return x.idx < y.idx
+ }
+ return x.n.Op != OCALL
+ })
+ flatConds = append(flatConds, c...)
+ }
var cond *Node
- if len(conds) == 0 {
+ if len(flatConds) == 0 {
cond = nodbool(true)
} else {
- cond = conds[0].n
- for _, c := range conds[1:] {
+ cond = flatConds[0].n
+ for _, c := range flatConds[1:] {
cond = nod(OANDAND, cond, c.n)
}
}
diff --git a/src/cmd/compile/internal/gc/builtin.go b/src/cmd/compile/internal/gc/builtin.go
index c2525395b0..2cf2f4687e 100644
--- a/src/cmd/compile/internal/gc/builtin.go
+++ b/src/cmd/compile/internal/gc/builtin.go
@@ -10,325 +10,329 @@ var runtimeDecls = [...]struct {
typ int
}{
{"newobject", funcTag, 4},
- {"panicdivide", funcTag, 5},
- {"panicshift", funcTag, 5},
- {"panicmakeslicelen", funcTag, 5},
- {"panicmakeslicecap", funcTag, 5},
- {"throwinit", funcTag, 5},
- {"panicwrap", funcTag, 5},
- {"gopanic", funcTag, 7},
- {"gorecover", funcTag, 10},
- {"goschedguarded", funcTag, 5},
- {"goPanicIndex", funcTag, 12},
- {"goPanicIndexU", funcTag, 14},
- {"goPanicSliceAlen", funcTag, 12},
- {"goPanicSliceAlenU", funcTag, 14},
- {"goPanicSliceAcap", funcTag, 12},
- {"goPanicSliceAcapU", funcTag, 14},
- {"goPanicSliceB", funcTag, 12},
- {"goPanicSliceBU", funcTag, 14},
- {"goPanicSlice3Alen", funcTag, 12},
- {"goPanicSlice3AlenU", funcTag, 14},
- {"goPanicSlice3Acap", funcTag, 12},
- {"goPanicSlice3AcapU", funcTag, 14},
- {"goPanicSlice3B", funcTag, 12},
- {"goPanicSlice3BU", funcTag, 14},
- {"goPanicSlice3C", funcTag, 12},
- {"goPanicSlice3CU", funcTag, 14},
- {"printbool", funcTag, 16},
- {"printfloat", funcTag, 18},
- {"printint", funcTag, 20},
- {"printhex", funcTag, 22},
- {"printuint", funcTag, 22},
- {"printcomplex", funcTag, 24},
- {"printstring", funcTag, 26},
- {"printpointer", funcTag, 27},
- {"printiface", funcTag, 27},
- {"printeface", funcTag, 27},
- {"printslice", funcTag, 27},
- {"printnl", funcTag, 5},
- {"printsp", funcTag, 5},
- {"printlock", funcTag, 5},
- {"printunlock", funcTag, 5},
- {"concatstring2", funcTag, 30},
- {"concatstring3", funcTag, 31},
- {"concatstring4", funcTag, 32},
- {"concatstring5", funcTag, 33},
- {"concatstrings", funcTag, 35},
- {"cmpstring", funcTag, 36},
- {"intstring", funcTag, 39},
- {"slicebytetostring", funcTag, 40},
- {"slicebytetostringtmp", funcTag, 41},
- {"slicerunetostring", funcTag, 44},
- {"stringtoslicebyte", funcTag, 46},
- {"stringtoslicerune", funcTag, 49},
- {"slicecopy", funcTag, 51},
- {"slicestringcopy", funcTag, 52},
- {"decoderune", funcTag, 53},
- {"countrunes", funcTag, 54},
- {"convI2I", funcTag, 55},
- {"convT16", funcTag, 57},
- {"convT32", funcTag, 57},
- {"convT64", funcTag, 57},
- {"convTstring", funcTag, 57},
- {"convTslice", funcTag, 57},
- {"convT2E", funcTag, 58},
- {"convT2Enoptr", funcTag, 58},
- {"convT2I", funcTag, 58},
- {"convT2Inoptr", funcTag, 58},
- {"assertE2I", funcTag, 55},
- {"assertE2I2", funcTag, 59},
- {"assertI2I", funcTag, 55},
- {"assertI2I2", funcTag, 59},
- {"panicdottypeE", funcTag, 60},
- {"panicdottypeI", funcTag, 60},
- {"panicnildottype", funcTag, 61},
- {"ifaceeq", funcTag, 63},
- {"efaceeq", funcTag, 63},
- {"fastrand", funcTag, 65},
- {"makemap64", funcTag, 67},
- {"makemap", funcTag, 68},
- {"makemap_small", funcTag, 69},
- {"mapaccess1", funcTag, 70},
- {"mapaccess1_fast32", funcTag, 71},
- {"mapaccess1_fast64", funcTag, 71},
- {"mapaccess1_faststr", funcTag, 71},
- {"mapaccess1_fat", funcTag, 72},
- {"mapaccess2", funcTag, 73},
- {"mapaccess2_fast32", funcTag, 74},
- {"mapaccess2_fast64", funcTag, 74},
- {"mapaccess2_faststr", funcTag, 74},
- {"mapaccess2_fat", funcTag, 75},
- {"mapassign", funcTag, 70},
- {"mapassign_fast32", funcTag, 71},
- {"mapassign_fast32ptr", funcTag, 71},
- {"mapassign_fast64", funcTag, 71},
- {"mapassign_fast64ptr", funcTag, 71},
- {"mapassign_faststr", funcTag, 71},
- {"mapiterinit", funcTag, 76},
- {"mapdelete", funcTag, 76},
- {"mapdelete_fast32", funcTag, 77},
- {"mapdelete_fast64", funcTag, 77},
- {"mapdelete_faststr", funcTag, 77},
- {"mapiternext", funcTag, 78},
- {"mapclear", funcTag, 79},
- {"makechan64", funcTag, 81},
- {"makechan", funcTag, 82},
- {"chanrecv1", funcTag, 84},
- {"chanrecv2", funcTag, 85},
- {"chansend1", funcTag, 87},
- {"closechan", funcTag, 27},
- {"writeBarrier", varTag, 89},
- {"typedmemmove", funcTag, 90},
- {"typedmemclr", funcTag, 91},
- {"typedslicecopy", funcTag, 92},
- {"selectnbsend", funcTag, 93},
- {"selectnbrecv", funcTag, 94},
- {"selectnbrecv2", funcTag, 96},
- {"selectsetpc", funcTag, 61},
- {"selectgo", funcTag, 97},
- {"block", funcTag, 5},
- {"makeslice", funcTag, 98},
- {"makeslice64", funcTag, 99},
- {"growslice", funcTag, 101},
- {"memmove", funcTag, 102},
- {"memclrNoHeapPointers", funcTag, 103},
- {"memclrHasPointers", funcTag, 103},
- {"memequal", funcTag, 104},
- {"memequal0", funcTag, 105},
- {"memequal8", funcTag, 105},
- {"memequal16", funcTag, 105},
- {"memequal32", funcTag, 105},
- {"memequal64", funcTag, 105},
- {"memequal128", funcTag, 105},
- {"f32equal", funcTag, 106},
- {"f64equal", funcTag, 106},
- {"c64equal", funcTag, 106},
- {"c128equal", funcTag, 106},
- {"strequal", funcTag, 106},
- {"interequal", funcTag, 106},
- {"nilinterequal", funcTag, 106},
- {"memhash", funcTag, 107},
- {"memhash0", funcTag, 108},
- {"memhash8", funcTag, 108},
- {"memhash16", funcTag, 108},
- {"memhash32", funcTag, 108},
- {"memhash64", funcTag, 108},
- {"memhash128", funcTag, 108},
- {"f32hash", funcTag, 108},
- {"f64hash", funcTag, 108},
- {"c64hash", funcTag, 108},
- {"c128hash", funcTag, 108},
- {"strhash", funcTag, 108},
- {"interhash", funcTag, 108},
- {"nilinterhash", funcTag, 108},
- {"int64div", funcTag, 109},
- {"uint64div", funcTag, 110},
- {"int64mod", funcTag, 109},
- {"uint64mod", funcTag, 110},
- {"float64toint64", funcTag, 111},
- {"float64touint64", funcTag, 112},
- {"float64touint32", funcTag, 113},
- {"int64tofloat64", funcTag, 114},
- {"uint64tofloat64", funcTag, 115},
- {"uint32tofloat64", funcTag, 116},
- {"complex128div", funcTag, 117},
- {"racefuncenter", funcTag, 118},
- {"racefuncenterfp", funcTag, 5},
- {"racefuncexit", funcTag, 5},
- {"raceread", funcTag, 118},
- {"racewrite", funcTag, 118},
- {"racereadrange", funcTag, 119},
- {"racewriterange", funcTag, 119},
- {"msanread", funcTag, 119},
- {"msanwrite", funcTag, 119},
- {"checkptrAlignment", funcTag, 120},
- {"checkptrArithmetic", funcTag, 122},
- {"libfuzzerTraceCmp1", funcTag, 124},
- {"libfuzzerTraceCmp2", funcTag, 126},
- {"libfuzzerTraceCmp4", funcTag, 127},
- {"libfuzzerTraceCmp8", funcTag, 128},
- {"libfuzzerTraceConstCmp1", funcTag, 124},
- {"libfuzzerTraceConstCmp2", funcTag, 126},
- {"libfuzzerTraceConstCmp4", funcTag, 127},
- {"libfuzzerTraceConstCmp8", funcTag, 128},
- {"x86HasPOPCNT", varTag, 15},
- {"x86HasSSE41", varTag, 15},
- {"x86HasFMA", varTag, 15},
- {"armHasVFPv4", varTag, 15},
- {"arm64HasATOMICS", varTag, 15},
+ {"mallocgc", funcTag, 8},
+ {"panicdivide", funcTag, 9},
+ {"panicshift", funcTag, 9},
+ {"panicmakeslicelen", funcTag, 9},
+ {"panicmakeslicecap", funcTag, 9},
+ {"throwinit", funcTag, 9},
+ {"panicwrap", funcTag, 9},
+ {"gopanic", funcTag, 11},
+ {"gorecover", funcTag, 14},
+ {"goschedguarded", funcTag, 9},
+ {"goPanicIndex", funcTag, 16},
+ {"goPanicIndexU", funcTag, 18},
+ {"goPanicSliceAlen", funcTag, 16},
+ {"goPanicSliceAlenU", funcTag, 18},
+ {"goPanicSliceAcap", funcTag, 16},
+ {"goPanicSliceAcapU", funcTag, 18},
+ {"goPanicSliceB", funcTag, 16},
+ {"goPanicSliceBU", funcTag, 18},
+ {"goPanicSlice3Alen", funcTag, 16},
+ {"goPanicSlice3AlenU", funcTag, 18},
+ {"goPanicSlice3Acap", funcTag, 16},
+ {"goPanicSlice3AcapU", funcTag, 18},
+ {"goPanicSlice3B", funcTag, 16},
+ {"goPanicSlice3BU", funcTag, 18},
+ {"goPanicSlice3C", funcTag, 16},
+ {"goPanicSlice3CU", funcTag, 18},
+ {"printbool", funcTag, 19},
+ {"printfloat", funcTag, 21},
+ {"printint", funcTag, 23},
+ {"printhex", funcTag, 25},
+ {"printuint", funcTag, 25},
+ {"printcomplex", funcTag, 27},
+ {"printstring", funcTag, 29},
+ {"printpointer", funcTag, 30},
+ {"printiface", funcTag, 30},
+ {"printeface", funcTag, 30},
+ {"printslice", funcTag, 30},
+ {"printnl", funcTag, 9},
+ {"printsp", funcTag, 9},
+ {"printlock", funcTag, 9},
+ {"printunlock", funcTag, 9},
+ {"concatstring2", funcTag, 33},
+ {"concatstring3", funcTag, 34},
+ {"concatstring4", funcTag, 35},
+ {"concatstring5", funcTag, 36},
+ {"concatstrings", funcTag, 38},
+ {"cmpstring", funcTag, 39},
+ {"intstring", funcTag, 42},
+ {"slicebytetostring", funcTag, 43},
+ {"slicebytetostringtmp", funcTag, 44},
+ {"slicerunetostring", funcTag, 47},
+ {"stringtoslicebyte", funcTag, 49},
+ {"stringtoslicerune", funcTag, 52},
+ {"slicecopy", funcTag, 53},
+ {"slicestringcopy", funcTag, 54},
+ {"decoderune", funcTag, 55},
+ {"countrunes", funcTag, 56},
+ {"convI2I", funcTag, 57},
+ {"convT16", funcTag, 58},
+ {"convT32", funcTag, 58},
+ {"convT64", funcTag, 58},
+ {"convTstring", funcTag, 58},
+ {"convTslice", funcTag, 58},
+ {"convT2E", funcTag, 59},
+ {"convT2Enoptr", funcTag, 59},
+ {"convT2I", funcTag, 59},
+ {"convT2Inoptr", funcTag, 59},
+ {"assertE2I", funcTag, 57},
+ {"assertE2I2", funcTag, 60},
+ {"assertI2I", funcTag, 57},
+ {"assertI2I2", funcTag, 60},
+ {"panicdottypeE", funcTag, 61},
+ {"panicdottypeI", funcTag, 61},
+ {"panicnildottype", funcTag, 62},
+ {"ifaceeq", funcTag, 64},
+ {"efaceeq", funcTag, 64},
+ {"fastrand", funcTag, 66},
+ {"makemap64", funcTag, 68},
+ {"makemap", funcTag, 69},
+ {"makemap_small", funcTag, 70},
+ {"mapaccess1", funcTag, 71},
+ {"mapaccess1_fast32", funcTag, 72},
+ {"mapaccess1_fast64", funcTag, 72},
+ {"mapaccess1_faststr", funcTag, 72},
+ {"mapaccess1_fat", funcTag, 73},
+ {"mapaccess2", funcTag, 74},
+ {"mapaccess2_fast32", funcTag, 75},
+ {"mapaccess2_fast64", funcTag, 75},
+ {"mapaccess2_faststr", funcTag, 75},
+ {"mapaccess2_fat", funcTag, 76},
+ {"mapassign", funcTag, 71},
+ {"mapassign_fast32", funcTag, 72},
+ {"mapassign_fast32ptr", funcTag, 72},
+ {"mapassign_fast64", funcTag, 72},
+ {"mapassign_fast64ptr", funcTag, 72},
+ {"mapassign_faststr", funcTag, 72},
+ {"mapiterinit", funcTag, 77},
+ {"mapdelete", funcTag, 77},
+ {"mapdelete_fast32", funcTag, 78},
+ {"mapdelete_fast64", funcTag, 78},
+ {"mapdelete_faststr", funcTag, 78},
+ {"mapiternext", funcTag, 79},
+ {"mapclear", funcTag, 80},
+ {"makechan64", funcTag, 82},
+ {"makechan", funcTag, 83},
+ {"chanrecv1", funcTag, 85},
+ {"chanrecv2", funcTag, 86},
+ {"chansend1", funcTag, 88},
+ {"closechan", funcTag, 30},
+ {"writeBarrier", varTag, 90},
+ {"typedmemmove", funcTag, 91},
+ {"typedmemclr", funcTag, 92},
+ {"typedslicecopy", funcTag, 93},
+ {"selectnbsend", funcTag, 94},
+ {"selectnbrecv", funcTag, 95},
+ {"selectnbrecv2", funcTag, 97},
+ {"selectsetpc", funcTag, 62},
+ {"selectgo", funcTag, 98},
+ {"block", funcTag, 9},
+ {"makeslice", funcTag, 99},
+ {"makeslice64", funcTag, 100},
+ {"makeslicecopy", funcTag, 101},
+ {"growslice", funcTag, 103},
+ {"memmove", funcTag, 104},
+ {"memclrNoHeapPointers", funcTag, 105},
+ {"memclrHasPointers", funcTag, 105},
+ {"memequal", funcTag, 106},
+ {"memequal0", funcTag, 107},
+ {"memequal8", funcTag, 107},
+ {"memequal16", funcTag, 107},
+ {"memequal32", funcTag, 107},
+ {"memequal64", funcTag, 107},
+ {"memequal128", funcTag, 107},
+ {"f32equal", funcTag, 108},
+ {"f64equal", funcTag, 108},
+ {"c64equal", funcTag, 108},
+ {"c128equal", funcTag, 108},
+ {"strequal", funcTag, 108},
+ {"interequal", funcTag, 108},
+ {"nilinterequal", funcTag, 108},
+ {"memhash", funcTag, 109},
+ {"memhash0", funcTag, 110},
+ {"memhash8", funcTag, 110},
+ {"memhash16", funcTag, 110},
+ {"memhash32", funcTag, 110},
+ {"memhash64", funcTag, 110},
+ {"memhash128", funcTag, 110},
+ {"f32hash", funcTag, 110},
+ {"f64hash", funcTag, 110},
+ {"c64hash", funcTag, 110},
+ {"c128hash", funcTag, 110},
+ {"strhash", funcTag, 110},
+ {"interhash", funcTag, 110},
+ {"nilinterhash", funcTag, 110},
+ {"int64div", funcTag, 111},
+ {"uint64div", funcTag, 112},
+ {"int64mod", funcTag, 111},
+ {"uint64mod", funcTag, 112},
+ {"float64toint64", funcTag, 113},
+ {"float64touint64", funcTag, 114},
+ {"float64touint32", funcTag, 115},
+ {"int64tofloat64", funcTag, 116},
+ {"uint64tofloat64", funcTag, 117},
+ {"uint32tofloat64", funcTag, 118},
+ {"complex128div", funcTag, 119},
+ {"racefuncenter", funcTag, 120},
+ {"racefuncenterfp", funcTag, 9},
+ {"racefuncexit", funcTag, 9},
+ {"raceread", funcTag, 120},
+ {"racewrite", funcTag, 120},
+ {"racereadrange", funcTag, 121},
+ {"racewriterange", funcTag, 121},
+ {"msanread", funcTag, 121},
+ {"msanwrite", funcTag, 121},
+ {"checkptrAlignment", funcTag, 122},
+ {"checkptrArithmetic", funcTag, 124},
+ {"libfuzzerTraceCmp1", funcTag, 126},
+ {"libfuzzerTraceCmp2", funcTag, 128},
+ {"libfuzzerTraceCmp4", funcTag, 129},
+ {"libfuzzerTraceCmp8", funcTag, 130},
+ {"libfuzzerTraceConstCmp1", funcTag, 126},
+ {"libfuzzerTraceConstCmp2", funcTag, 128},
+ {"libfuzzerTraceConstCmp4", funcTag, 129},
+ {"libfuzzerTraceConstCmp8", funcTag, 130},
+ {"x86HasPOPCNT", varTag, 6},
+ {"x86HasSSE41", varTag, 6},
+ {"x86HasFMA", varTag, 6},
+ {"armHasVFPv4", varTag, 6},
+ {"arm64HasATOMICS", varTag, 6},
}
func runtimeTypes() []*types.Type {
- var typs [129]*types.Type
+ var typs [131]*types.Type
typs[0] = types.Bytetype
typs[1] = types.NewPtr(typs[0])
typs[2] = types.Types[TANY]
typs[3] = types.NewPtr(typs[2])
typs[4] = functype(nil, []*Node{anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[5] = functype(nil, nil, nil)
- typs[6] = types.Types[TINTER]
- typs[7] = functype(nil, []*Node{anonfield(typs[6])}, nil)
- typs[8] = types.Types[TINT32]
- typs[9] = types.NewPtr(typs[8])
- typs[10] = functype(nil, []*Node{anonfield(typs[9])}, []*Node{anonfield(typs[6])})
- typs[11] = types.Types[TINT]
- typs[12] = functype(nil, []*Node{anonfield(typs[11]), anonfield(typs[11])}, nil)
- typs[13] = types.Types[TUINT]
- typs[14] = functype(nil, []*Node{anonfield(typs[13]), anonfield(typs[11])}, nil)
- typs[15] = types.Types[TBOOL]
- typs[16] = functype(nil, []*Node{anonfield(typs[15])}, nil)
- typs[17] = types.Types[TFLOAT64]
- typs[18] = functype(nil, []*Node{anonfield(typs[17])}, nil)
- typs[19] = types.Types[TINT64]
- typs[20] = functype(nil, []*Node{anonfield(typs[19])}, nil)
- typs[21] = types.Types[TUINT64]
- typs[22] = functype(nil, []*Node{anonfield(typs[21])}, nil)
- typs[23] = types.Types[TCOMPLEX128]
- typs[24] = functype(nil, []*Node{anonfield(typs[23])}, nil)
- typs[25] = types.Types[TSTRING]
- typs[26] = functype(nil, []*Node{anonfield(typs[25])}, nil)
- typs[27] = functype(nil, []*Node{anonfield(typs[2])}, nil)
- typs[28] = types.NewArray(typs[0], 32)
- typs[29] = types.NewPtr(typs[28])
- typs[30] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
- typs[31] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
- typs[32] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
- typs[33] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[25])})
- typs[34] = types.NewSlice(typs[25])
- typs[35] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[34])}, []*Node{anonfield(typs[25])})
- typs[36] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
- typs[37] = types.NewArray(typs[0], 4)
- typs[38] = types.NewPtr(typs[37])
- typs[39] = functype(nil, []*Node{anonfield(typs[38]), anonfield(typs[19])}, []*Node{anonfield(typs[25])})
- typs[40] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
- typs[41] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[25])})
- typs[42] = types.Runetype
- typs[43] = types.NewSlice(typs[42])
- typs[44] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[43])}, []*Node{anonfield(typs[25])})
- typs[45] = types.NewSlice(typs[0])
- typs[46] = functype(nil, []*Node{anonfield(typs[29]), anonfield(typs[25])}, []*Node{anonfield(typs[45])})
- typs[47] = types.NewArray(typs[42], 32)
- typs[48] = types.NewPtr(typs[47])
- typs[49] = functype(nil, []*Node{anonfield(typs[48]), anonfield(typs[25])}, []*Node{anonfield(typs[43])})
- typs[50] = types.Types[TUINTPTR]
- typs[51] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[50])}, []*Node{anonfield(typs[11])})
- typs[52] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[25])}, []*Node{anonfield(typs[11])})
- typs[53] = functype(nil, []*Node{anonfield(typs[25]), anonfield(typs[11])}, []*Node{anonfield(typs[42]), anonfield(typs[11])})
- typs[54] = functype(nil, []*Node{anonfield(typs[25])}, []*Node{anonfield(typs[11])})
- typs[55] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
- typs[56] = types.Types[TUNSAFEPTR]
- typs[57] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[56])})
- typs[58] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
- typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[15])})
- typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
- typs[61] = functype(nil, []*Node{anonfield(typs[1])}, nil)
- typs[62] = types.NewPtr(typs[50])
- typs[63] = functype(nil, []*Node{anonfield(typs[62]), anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
- typs[64] = types.Types[TUINT32]
- typs[65] = functype(nil, nil, []*Node{anonfield(typs[64])})
- typs[66] = types.NewMap(typs[2], typs[2])
- typs[67] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
- typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[3])}, []*Node{anonfield(typs[66])})
- typs[69] = functype(nil, nil, []*Node{anonfield(typs[66])})
- typs[70] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
- typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
- typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
- typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
- typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
- typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[15])})
- typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[3])}, nil)
- typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66]), anonfield(typs[2])}, nil)
- typs[78] = functype(nil, []*Node{anonfield(typs[3])}, nil)
- typs[79] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[66])}, nil)
- typs[80] = types.NewChan(typs[2], types.Cboth)
- typs[81] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19])}, []*Node{anonfield(typs[80])})
- typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[80])})
- typs[83] = types.NewChan(typs[2], types.Crecv)
- typs[84] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, nil)
- typs[85] = functype(nil, []*Node{anonfield(typs[83]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
- typs[86] = types.NewChan(typs[2], types.Csend)
- typs[87] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, nil)
- typs[88] = types.NewArray(typs[0], 3)
- typs[89] = tostruct([]*Node{namedfield("enabled", typs[15]), namedfield("pad", typs[88]), namedfield("needed", typs[15]), namedfield("cgo", typs[15]), namedfield("alignme", typs[21])})
- typs[90] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
- typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
- typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[11]), anonfield(typs[3]), anonfield(typs[11])}, []*Node{anonfield(typs[11])})
- typs[93] = functype(nil, []*Node{anonfield(typs[86]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
- typs[94] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
- typs[95] = types.NewPtr(typs[15])
- typs[96] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[95]), anonfield(typs[83])}, []*Node{anonfield(typs[15])})
- typs[97] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[11])}, []*Node{anonfield(typs[11]), anonfield(typs[15])})
- typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[11]), anonfield(typs[11])}, []*Node{anonfield(typs[56])})
- typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[56])})
- typs[100] = types.NewSlice(typs[2])
- typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[100]), anonfield(typs[11])}, []*Node{anonfield(typs[100])})
- typs[102] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, nil)
- typs[103] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, nil)
- typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[50])}, []*Node{anonfield(typs[15])})
- typs[105] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[15])})
- typs[106] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[56])}, []*Node{anonfield(typs[15])})
- typs[107] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
- typs[108] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[50])}, []*Node{anonfield(typs[50])})
- typs[109] = functype(nil, []*Node{anonfield(typs[19]), anonfield(typs[19])}, []*Node{anonfield(typs[19])})
- typs[110] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, []*Node{anonfield(typs[21])})
- typs[111] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[19])})
- typs[112] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[21])})
- typs[113] = functype(nil, []*Node{anonfield(typs[17])}, []*Node{anonfield(typs[64])})
- typs[114] = functype(nil, []*Node{anonfield(typs[19])}, []*Node{anonfield(typs[17])})
- typs[115] = functype(nil, []*Node{anonfield(typs[21])}, []*Node{anonfield(typs[17])})
- typs[116] = functype(nil, []*Node{anonfield(typs[64])}, []*Node{anonfield(typs[17])})
- typs[117] = functype(nil, []*Node{anonfield(typs[23]), anonfield(typs[23])}, []*Node{anonfield(typs[23])})
- typs[118] = functype(nil, []*Node{anonfield(typs[50])}, nil)
- typs[119] = functype(nil, []*Node{anonfield(typs[50]), anonfield(typs[50])}, nil)
- typs[120] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[1]), anonfield(typs[50])}, nil)
- typs[121] = types.NewSlice(typs[56])
- typs[122] = functype(nil, []*Node{anonfield(typs[56]), anonfield(typs[121])}, nil)
- typs[123] = types.Types[TUINT8]
- typs[124] = functype(nil, []*Node{anonfield(typs[123]), anonfield(typs[123])}, nil)
- typs[125] = types.Types[TUINT16]
+ typs[5] = types.Types[TUINTPTR]
+ typs[6] = types.Types[TBOOL]
+ typs[7] = types.Types[TUNSAFEPTR]
+ typs[8] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[1]), anonfield(typs[6])}, []*Node{anonfield(typs[7])})
+ typs[9] = functype(nil, nil, nil)
+ typs[10] = types.Types[TINTER]
+ typs[11] = functype(nil, []*Node{anonfield(typs[10])}, nil)
+ typs[12] = types.Types[TINT32]
+ typs[13] = types.NewPtr(typs[12])
+ typs[14] = functype(nil, []*Node{anonfield(typs[13])}, []*Node{anonfield(typs[10])})
+ typs[15] = types.Types[TINT]
+ typs[16] = functype(nil, []*Node{anonfield(typs[15]), anonfield(typs[15])}, nil)
+ typs[17] = types.Types[TUINT]
+ typs[18] = functype(nil, []*Node{anonfield(typs[17]), anonfield(typs[15])}, nil)
+ typs[19] = functype(nil, []*Node{anonfield(typs[6])}, nil)
+ typs[20] = types.Types[TFLOAT64]
+ typs[21] = functype(nil, []*Node{anonfield(typs[20])}, nil)
+ typs[22] = types.Types[TINT64]
+ typs[23] = functype(nil, []*Node{anonfield(typs[22])}, nil)
+ typs[24] = types.Types[TUINT64]
+ typs[25] = functype(nil, []*Node{anonfield(typs[24])}, nil)
+ typs[26] = types.Types[TCOMPLEX128]
+ typs[27] = functype(nil, []*Node{anonfield(typs[26])}, nil)
+ typs[28] = types.Types[TSTRING]
+ typs[29] = functype(nil, []*Node{anonfield(typs[28])}, nil)
+ typs[30] = functype(nil, []*Node{anonfield(typs[2])}, nil)
+ typs[31] = types.NewArray(typs[0], 32)
+ typs[32] = types.NewPtr(typs[31])
+ typs[33] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[34] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[35] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[36] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[28])})
+ typs[37] = types.NewSlice(typs[28])
+ typs[38] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[37])}, []*Node{anonfield(typs[28])})
+ typs[39] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[40] = types.NewArray(typs[0], 4)
+ typs[41] = types.NewPtr(typs[40])
+ typs[42] = functype(nil, []*Node{anonfield(typs[41]), anonfield(typs[22])}, []*Node{anonfield(typs[28])})
+ typs[43] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[44] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[28])})
+ typs[45] = types.Runetype
+ typs[46] = types.NewSlice(typs[45])
+ typs[47] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[46])}, []*Node{anonfield(typs[28])})
+ typs[48] = types.NewSlice(typs[0])
+ typs[49] = functype(nil, []*Node{anonfield(typs[32]), anonfield(typs[28])}, []*Node{anonfield(typs[48])})
+ typs[50] = types.NewArray(typs[45], 32)
+ typs[51] = types.NewPtr(typs[50])
+ typs[52] = functype(nil, []*Node{anonfield(typs[51]), anonfield(typs[28])}, []*Node{anonfield(typs[46])})
+ typs[53] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[5])}, []*Node{anonfield(typs[15])})
+ typs[54] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[55] = functype(nil, []*Node{anonfield(typs[28]), anonfield(typs[15])}, []*Node{anonfield(typs[45]), anonfield(typs[15])})
+ typs[56] = functype(nil, []*Node{anonfield(typs[28])}, []*Node{anonfield(typs[15])})
+ typs[57] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2])})
+ typs[58] = functype(nil, []*Node{anonfield(typs[2])}, []*Node{anonfield(typs[7])})
+ typs[59] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, []*Node{anonfield(typs[2])})
+ typs[60] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[2])}, []*Node{anonfield(typs[2]), anonfield(typs[6])})
+ typs[61] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[1])}, nil)
+ typs[62] = functype(nil, []*Node{anonfield(typs[1])}, nil)
+ typs[63] = types.NewPtr(typs[5])
+ typs[64] = functype(nil, []*Node{anonfield(typs[63]), anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[65] = types.Types[TUINT32]
+ typs[66] = functype(nil, nil, []*Node{anonfield(typs[65])})
+ typs[67] = types.NewMap(typs[2], typs[2])
+ typs[68] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[69] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[3])}, []*Node{anonfield(typs[67])})
+ typs[70] = functype(nil, nil, []*Node{anonfield(typs[67])})
+ typs[71] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3])})
+ typs[72] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3])})
+ typs[73] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3])})
+ typs[74] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[75] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[76] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3]), anonfield(typs[1])}, []*Node{anonfield(typs[3]), anonfield(typs[6])})
+ typs[77] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[3])}, nil)
+ typs[78] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67]), anonfield(typs[2])}, nil)
+ typs[79] = functype(nil, []*Node{anonfield(typs[3])}, nil)
+ typs[80] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[67])}, nil)
+ typs[81] = types.NewChan(typs[2], types.Cboth)
+ typs[82] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22])}, []*Node{anonfield(typs[81])})
+ typs[83] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[81])})
+ typs[84] = types.NewChan(typs[2], types.Crecv)
+ typs[85] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, nil)
+ typs[86] = functype(nil, []*Node{anonfield(typs[84]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[87] = types.NewChan(typs[2], types.Csend)
+ typs[88] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, nil)
+ typs[89] = types.NewArray(typs[0], 3)
+ typs[90] = tostruct([]*Node{namedfield("enabled", typs[6]), namedfield("pad", typs[89]), namedfield("needed", typs[6]), namedfield("cgo", typs[6]), namedfield("alignme", typs[24])})
+ typs[91] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[3])}, nil)
+ typs[92] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3])}, nil)
+ typs[93] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[3]), anonfield(typs[15]), anonfield(typs[3]), anonfield(typs[15])}, []*Node{anonfield(typs[15])})
+ typs[94] = functype(nil, []*Node{anonfield(typs[87]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[95] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[96] = types.NewPtr(typs[6])
+ typs[97] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[96]), anonfield(typs[84])}, []*Node{anonfield(typs[6])})
+ typs[98] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[1]), anonfield(typs[15])}, []*Node{anonfield(typs[15]), anonfield(typs[6])})
+ typs[99] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15])}, []*Node{anonfield(typs[7])})
+ typs[100] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[7])})
+ typs[101] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[15]), anonfield(typs[15]), anonfield(typs[7])}, []*Node{anonfield(typs[7])})
+ typs[102] = types.NewSlice(typs[2])
+ typs[103] = functype(nil, []*Node{anonfield(typs[1]), anonfield(typs[102]), anonfield(typs[15])}, []*Node{anonfield(typs[102])})
+ typs[104] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, nil)
+ typs[105] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, nil)
+ typs[106] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3]), anonfield(typs[5])}, []*Node{anonfield(typs[6])})
+ typs[107] = functype(nil, []*Node{anonfield(typs[3]), anonfield(typs[3])}, []*Node{anonfield(typs[6])})
+ typs[108] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[7])}, []*Node{anonfield(typs[6])})
+ typs[109] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[110] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[5])}, []*Node{anonfield(typs[5])})
+ typs[111] = functype(nil, []*Node{anonfield(typs[22]), anonfield(typs[22])}, []*Node{anonfield(typs[22])})
+ typs[112] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, []*Node{anonfield(typs[24])})
+ typs[113] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[22])})
+ typs[114] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[24])})
+ typs[115] = functype(nil, []*Node{anonfield(typs[20])}, []*Node{anonfield(typs[65])})
+ typs[116] = functype(nil, []*Node{anonfield(typs[22])}, []*Node{anonfield(typs[20])})
+ typs[117] = functype(nil, []*Node{anonfield(typs[24])}, []*Node{anonfield(typs[20])})
+ typs[118] = functype(nil, []*Node{anonfield(typs[65])}, []*Node{anonfield(typs[20])})
+ typs[119] = functype(nil, []*Node{anonfield(typs[26]), anonfield(typs[26])}, []*Node{anonfield(typs[26])})
+ typs[120] = functype(nil, []*Node{anonfield(typs[5])}, nil)
+ typs[121] = functype(nil, []*Node{anonfield(typs[5]), anonfield(typs[5])}, nil)
+ typs[122] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[1]), anonfield(typs[5])}, nil)
+ typs[123] = types.NewSlice(typs[7])
+ typs[124] = functype(nil, []*Node{anonfield(typs[7]), anonfield(typs[123])}, nil)
+ typs[125] = types.Types[TUINT8]
typs[126] = functype(nil, []*Node{anonfield(typs[125]), anonfield(typs[125])}, nil)
- typs[127] = functype(nil, []*Node{anonfield(typs[64]), anonfield(typs[64])}, nil)
- typs[128] = functype(nil, []*Node{anonfield(typs[21]), anonfield(typs[21])}, nil)
+ typs[127] = types.Types[TUINT16]
+ typs[128] = functype(nil, []*Node{anonfield(typs[127]), anonfield(typs[127])}, nil)
+ typs[129] = functype(nil, []*Node{anonfield(typs[65]), anonfield(typs[65])}, nil)
+ typs[130] = functype(nil, []*Node{anonfield(typs[24]), anonfield(typs[24])}, nil)
return typs[:]
}
diff --git a/src/cmd/compile/internal/gc/builtin/runtime.go b/src/cmd/compile/internal/gc/builtin/runtime.go
index 3475d4c375..00448272c5 100644
--- a/src/cmd/compile/internal/gc/builtin/runtime.go
+++ b/src/cmd/compile/internal/gc/builtin/runtime.go
@@ -15,6 +15,7 @@ package runtime
import "unsafe"
func newobject(typ *byte) *any
+func mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
func panicdivide()
func panicshift()
func panicmakeslicelen()
@@ -174,6 +175,7 @@ func block()
func makeslice(typ *byte, len int, cap int) unsafe.Pointer
func makeslice64(typ *byte, len int64, cap int64) unsafe.Pointer
+func makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
func growslice(typ *byte, old []any, cap int) (ary []any)
func memmove(to *any, frm *any, length uintptr)
func memclrNoHeapPointers(ptr unsafe.Pointer, n uintptr)
diff --git a/src/cmd/compile/internal/gc/esc.go b/src/cmd/compile/internal/gc/esc.go
index 8e781a7997..f3e9ab78ef 100644
--- a/src/cmd/compile/internal/gc/esc.go
+++ b/src/cmd/compile/internal/gc/esc.go
@@ -141,13 +141,13 @@ func isSelfAssign(dst, src *Node) bool {
return samesafeexpr(dst.Left, src.Left)
}
-// mayAffectMemory reports whether n evaluation may affect program memory state.
-// If expression can't affect it, then it can be safely ignored by the escape analysis.
+// mayAffectMemory reports whether evaluation of n may affect the program's
+// memory state. If the expression can't affect memory state, then it can be
+// safely ignored by the escape analysis.
func mayAffectMemory(n *Node) bool {
- // We may want to use "memory safe" black list instead of general
- // "side-effect free", which can include all calls and other ops
- // that can affect allocate or change global state.
- // It's safer to start from a whitelist for now.
+ // We may want to use a list of "memory safe" ops instead of generally
+ // "side-effect free", which would include all calls and other ops that can
+ // allocate or change global state. For now, it's safer to start with the latter.
//
// We're ignoring things like division by zero, index out of range,
// and nil pointer dereference here.
diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go
index 63a58d0a06..d6cc9fa4cf 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1165,92 +1165,93 @@ func (n *Node) stmtfmt(s fmt.State, mode fmtMode) {
}
var opprec = []int{
- OALIGNOF: 8,
- OAPPEND: 8,
- OBYTES2STR: 8,
- OARRAYLIT: 8,
- OSLICELIT: 8,
- ORUNES2STR: 8,
- OCALLFUNC: 8,
- OCALLINTER: 8,
- OCALLMETH: 8,
- OCALL: 8,
- OCAP: 8,
- OCLOSE: 8,
- OCONVIFACE: 8,
- OCONVNOP: 8,
- OCONV: 8,
- OCOPY: 8,
- ODELETE: 8,
- OGETG: 8,
- OLEN: 8,
- OLITERAL: 8,
- OMAKESLICE: 8,
- OMAKE: 8,
- OMAPLIT: 8,
- ONAME: 8,
- ONEW: 8,
- ONONAME: 8,
- OOFFSETOF: 8,
- OPACK: 8,
- OPANIC: 8,
- OPAREN: 8,
- OPRINTN: 8,
- OPRINT: 8,
- ORUNESTR: 8,
- OSIZEOF: 8,
- OSTR2BYTES: 8,
- OSTR2RUNES: 8,
- OSTRUCTLIT: 8,
- OTARRAY: 8,
- OTCHAN: 8,
- OTFUNC: 8,
- OTINTER: 8,
- OTMAP: 8,
- OTSTRUCT: 8,
- OINDEXMAP: 8,
- OINDEX: 8,
- OSLICE: 8,
- OSLICESTR: 8,
- OSLICEARR: 8,
- OSLICE3: 8,
- OSLICE3ARR: 8,
- OSLICEHEADER: 8,
- ODOTINTER: 8,
- ODOTMETH: 8,
- ODOTPTR: 8,
- ODOTTYPE2: 8,
- ODOTTYPE: 8,
- ODOT: 8,
- OXDOT: 8,
- OCALLPART: 8,
- OPLUS: 7,
- ONOT: 7,
- OBITNOT: 7,
- ONEG: 7,
- OADDR: 7,
- ODEREF: 7,
- ORECV: 7,
- OMUL: 6,
- ODIV: 6,
- OMOD: 6,
- OLSH: 6,
- ORSH: 6,
- OAND: 6,
- OANDNOT: 6,
- OADD: 5,
- OSUB: 5,
- OOR: 5,
- OXOR: 5,
- OEQ: 4,
- OLT: 4,
- OLE: 4,
- OGE: 4,
- OGT: 4,
- ONE: 4,
- OSEND: 3,
- OANDAND: 2,
- OOROR: 1,
+ OALIGNOF: 8,
+ OAPPEND: 8,
+ OBYTES2STR: 8,
+ OARRAYLIT: 8,
+ OSLICELIT: 8,
+ ORUNES2STR: 8,
+ OCALLFUNC: 8,
+ OCALLINTER: 8,
+ OCALLMETH: 8,
+ OCALL: 8,
+ OCAP: 8,
+ OCLOSE: 8,
+ OCONVIFACE: 8,
+ OCONVNOP: 8,
+ OCONV: 8,
+ OCOPY: 8,
+ ODELETE: 8,
+ OGETG: 8,
+ OLEN: 8,
+ OLITERAL: 8,
+ OMAKESLICE: 8,
+ OMAKESLICECOPY: 8,
+ OMAKE: 8,
+ OMAPLIT: 8,
+ ONAME: 8,
+ ONEW: 8,
+ ONONAME: 8,
+ OOFFSETOF: 8,
+ OPACK: 8,
+ OPANIC: 8,
+ OPAREN: 8,
+ OPRINTN: 8,
+ OPRINT: 8,
+ ORUNESTR: 8,
+ OSIZEOF: 8,
+ OSTR2BYTES: 8,
+ OSTR2RUNES: 8,
+ OSTRUCTLIT: 8,
+ OTARRAY: 8,
+ OTCHAN: 8,
+ OTFUNC: 8,
+ OTINTER: 8,
+ OTMAP: 8,
+ OTSTRUCT: 8,
+ OINDEXMAP: 8,
+ OINDEX: 8,
+ OSLICE: 8,
+ OSLICESTR: 8,
+ OSLICEARR: 8,
+ OSLICE3: 8,
+ OSLICE3ARR: 8,
+ OSLICEHEADER: 8,
+ ODOTINTER: 8,
+ ODOTMETH: 8,
+ ODOTPTR: 8,
+ ODOTTYPE2: 8,
+ ODOTTYPE: 8,
+ ODOT: 8,
+ OXDOT: 8,
+ OCALLPART: 8,
+ OPLUS: 7,
+ ONOT: 7,
+ OBITNOT: 7,
+ ONEG: 7,
+ OADDR: 7,
+ ODEREF: 7,
+ ORECV: 7,
+ OMUL: 6,
+ ODIV: 6,
+ OMOD: 6,
+ OLSH: 6,
+ ORSH: 6,
+ OAND: 6,
+ OANDNOT: 6,
+ OADD: 5,
+ OSUB: 5,
+ OOR: 5,
+ OXOR: 5,
+ OEQ: 4,
+ OLT: 4,
+ OLE: 4,
+ OGE: 4,
+ OGT: 4,
+ ONE: 4,
+ OSEND: 3,
+ OANDAND: 2,
+ OOROR: 1,
// Statements handled by stmtfmt
OAS: -1,
@@ -1572,6 +1573,9 @@ func (n *Node) exprfmt(s fmt.State, prec int, mode fmtMode) {
}
mode.Fprintf(s, "make(%v)", n.Type)
+ case OMAKESLICECOPY:
+ mode.Fprintf(s, "makeslicecopy(%v, %v, %v)", n.Type, n.Left, n.Right)
+
case OPLUS, ONEG, OADDR, OBITNOT, ODEREF, ONOT, ORECV:
// Unary
mode.Fprintf(s, "%#v", n.Op)
diff --git a/src/cmd/compile/internal/gc/gsubr.go b/src/cmd/compile/internal/gc/gsubr.go
index bb1393ae6a..336e870bbd 100644
--- a/src/cmd/compile/internal/gc/gsubr.go
+++ b/src/cmd/compile/internal/gc/gsubr.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6c/txt.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/txt.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/txt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/compile/internal/gc/noder.go b/src/cmd/compile/internal/gc/noder.go
index 31fe46ad62..802aab2268 100644
--- a/src/cmd/compile/internal/gc/noder.go
+++ b/src/cmd/compile/internal/gc/noder.go
@@ -44,7 +44,7 @@ func parseFiles(filenames []string) uint {
f, err := os.Open(filename)
if err != nil {
- p.error(syntax.Error{Pos: syntax.MakePos(base, 0, 0), Msg: err.Error()})
+ p.error(syntax.Error{Msg: err.Error()})
return
}
defer f.Close()
diff --git a/src/cmd/compile/internal/gc/op_string.go b/src/cmd/compile/internal/gc/op_string.go
index 3622884527..41d588309c 100644
--- a/src/cmd/compile/internal/gc/op_string.go
+++ b/src/cmd/compile/internal/gc/op_string.go
@@ -82,89 +82,90 @@ func _() {
_ = x[OMAKECHAN-71]
_ = x[OMAKEMAP-72]
_ = x[OMAKESLICE-73]
- _ = x[OMUL-74]
- _ = x[ODIV-75]
- _ = x[OMOD-76]
- _ = x[OLSH-77]
- _ = x[ORSH-78]
- _ = x[OAND-79]
- _ = x[OANDNOT-80]
- _ = x[ONEW-81]
- _ = x[ONEWOBJ-82]
- _ = x[ONOT-83]
- _ = x[OBITNOT-84]
- _ = x[OPLUS-85]
- _ = x[ONEG-86]
- _ = x[OOROR-87]
- _ = x[OPANIC-88]
- _ = x[OPRINT-89]
- _ = x[OPRINTN-90]
- _ = x[OPAREN-91]
- _ = x[OSEND-92]
- _ = x[OSLICE-93]
- _ = x[OSLICEARR-94]
- _ = x[OSLICESTR-95]
- _ = x[OSLICE3-96]
- _ = x[OSLICE3ARR-97]
- _ = x[OSLICEHEADER-98]
- _ = x[ORECOVER-99]
- _ = x[ORECV-100]
- _ = x[ORUNESTR-101]
- _ = x[OSELRECV-102]
- _ = x[OSELRECV2-103]
- _ = x[OIOTA-104]
- _ = x[OREAL-105]
- _ = x[OIMAG-106]
- _ = x[OCOMPLEX-107]
- _ = x[OALIGNOF-108]
- _ = x[OOFFSETOF-109]
- _ = x[OSIZEOF-110]
- _ = x[OBLOCK-111]
- _ = x[OBREAK-112]
- _ = x[OCASE-113]
- _ = x[OCONTINUE-114]
- _ = x[ODEFER-115]
- _ = x[OEMPTY-116]
- _ = x[OFALL-117]
- _ = x[OFOR-118]
- _ = x[OFORUNTIL-119]
- _ = x[OGOTO-120]
- _ = x[OIF-121]
- _ = x[OLABEL-122]
- _ = x[OGO-123]
- _ = x[ORANGE-124]
- _ = x[ORETURN-125]
- _ = x[OSELECT-126]
- _ = x[OSWITCH-127]
- _ = x[OTYPESW-128]
- _ = x[OTCHAN-129]
- _ = x[OTMAP-130]
- _ = x[OTSTRUCT-131]
- _ = x[OTINTER-132]
- _ = x[OTFUNC-133]
- _ = x[OTARRAY-134]
- _ = x[ODDD-135]
- _ = x[OINLCALL-136]
- _ = x[OEFACE-137]
- _ = x[OITAB-138]
- _ = x[OIDATA-139]
- _ = x[OSPTR-140]
- _ = x[OCLOSUREVAR-141]
- _ = x[OCFUNC-142]
- _ = x[OCHECKNIL-143]
- _ = x[OVARDEF-144]
- _ = x[OVARKILL-145]
- _ = x[OVARLIVE-146]
- _ = x[ORESULT-147]
- _ = x[OINLMARK-148]
- _ = x[ORETJMP-149]
- _ = x[OGETG-150]
- _ = x[OEND-151]
+ _ = x[OMAKESLICECOPY-74]
+ _ = x[OMUL-75]
+ _ = x[ODIV-76]
+ _ = x[OMOD-77]
+ _ = x[OLSH-78]
+ _ = x[ORSH-79]
+ _ = x[OAND-80]
+ _ = x[OANDNOT-81]
+ _ = x[ONEW-82]
+ _ = x[ONEWOBJ-83]
+ _ = x[ONOT-84]
+ _ = x[OBITNOT-85]
+ _ = x[OPLUS-86]
+ _ = x[ONEG-87]
+ _ = x[OOROR-88]
+ _ = x[OPANIC-89]
+ _ = x[OPRINT-90]
+ _ = x[OPRINTN-91]
+ _ = x[OPAREN-92]
+ _ = x[OSEND-93]
+ _ = x[OSLICE-94]
+ _ = x[OSLICEARR-95]
+ _ = x[OSLICESTR-96]
+ _ = x[OSLICE3-97]
+ _ = x[OSLICE3ARR-98]
+ _ = x[OSLICEHEADER-99]
+ _ = x[ORECOVER-100]
+ _ = x[ORECV-101]
+ _ = x[ORUNESTR-102]
+ _ = x[OSELRECV-103]
+ _ = x[OSELRECV2-104]
+ _ = x[OIOTA-105]
+ _ = x[OREAL-106]
+ _ = x[OIMAG-107]
+ _ = x[OCOMPLEX-108]
+ _ = x[OALIGNOF-109]
+ _ = x[OOFFSETOF-110]
+ _ = x[OSIZEOF-111]
+ _ = x[OBLOCK-112]
+ _ = x[OBREAK-113]
+ _ = x[OCASE-114]
+ _ = x[OCONTINUE-115]
+ _ = x[ODEFER-116]
+ _ = x[OEMPTY-117]
+ _ = x[OFALL-118]
+ _ = x[OFOR-119]
+ _ = x[OFORUNTIL-120]
+ _ = x[OGOTO-121]
+ _ = x[OIF-122]
+ _ = x[OLABEL-123]
+ _ = x[OGO-124]
+ _ = x[ORANGE-125]
+ _ = x[ORETURN-126]
+ _ = x[OSELECT-127]
+ _ = x[OSWITCH-128]
+ _ = x[OTYPESW-129]
+ _ = x[OTCHAN-130]
+ _ = x[OTMAP-131]
+ _ = x[OTSTRUCT-132]
+ _ = x[OTINTER-133]
+ _ = x[OTFUNC-134]
+ _ = x[OTARRAY-135]
+ _ = x[ODDD-136]
+ _ = x[OINLCALL-137]
+ _ = x[OEFACE-138]
+ _ = x[OITAB-139]
+ _ = x[OIDATA-140]
+ _ = x[OSPTR-141]
+ _ = x[OCLOSUREVAR-142]
+ _ = x[OCFUNC-143]
+ _ = x[OCHECKNIL-144]
+ _ = x[OVARDEF-145]
+ _ = x[OVARKILL-146]
+ _ = x[OVARLIVE-147]
+ _ = x[ORESULT-148]
+ _ = x[OINLMARK-149]
+ _ = x[ORETJMP-150]
+ _ = x[OGETG-151]
+ _ = x[OEND-152]
}
-const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
+const _Op_name = "XXXNAMENONAMETYPEPACKLITERALADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCALLPARTCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVNOPCOPYDCLDCLFUNCDCLFIELDDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNEWOBJNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECVRUNESTRSELRECVSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFBLOCKBREAKCASECONTINUEDEFEREMPTYFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWTCHANTMAPTSTRUCTTINTERTFUNCTARRAYDDDINLCALLEFACEITABIDATASPTRCLOSUREVARCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKRETJMPGETGEND"
-var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 439, 442, 445, 448, 451, 454, 460, 463, 469, 472, 478, 482, 485, 489, 494, 499, 505, 510, 514, 519, 527, 535, 541, 550, 561, 568, 572, 579, 586, 594, 598, 602, 606, 613, 620, 628, 634, 639, 644, 648, 656, 661, 666, 670, 673, 681, 685, 687, 692, 694, 699, 705, 711, 717, 723, 728, 732, 739, 745, 750, 756, 759, 766, 771, 775, 780, 784, 794, 799, 807, 813, 820, 827, 833, 840, 846, 850, 853}
+var _Op_index = [...]uint16{0, 3, 7, 13, 17, 21, 28, 31, 34, 36, 39, 45, 49, 55, 61, 70, 82, 91, 100, 112, 121, 123, 126, 136, 143, 150, 157, 161, 165, 173, 181, 190, 198, 201, 206, 213, 220, 226, 235, 243, 251, 257, 261, 270, 277, 281, 284, 291, 299, 307, 314, 320, 323, 329, 336, 344, 348, 355, 363, 365, 367, 369, 371, 373, 375, 380, 385, 393, 396, 405, 408, 412, 420, 427, 436, 449, 452, 455, 458, 461, 464, 467, 473, 476, 482, 485, 491, 495, 498, 502, 507, 512, 518, 523, 527, 532, 540, 548, 554, 563, 574, 581, 585, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 652, 657, 661, 669, 674, 679, 683, 686, 694, 698, 700, 705, 707, 712, 718, 724, 730, 736, 741, 745, 752, 758, 763, 769, 772, 779, 784, 788, 793, 797, 807, 812, 820, 826, 833, 840, 846, 853, 859, 863, 866}
func (i Op) String() string {
if i >= Op(len(_Op_index)-1) {
diff --git a/src/cmd/compile/internal/gc/order.go b/src/cmd/compile/internal/gc/order.go
index 8bce71b883..6b6107290a 100644
--- a/src/cmd/compile/internal/gc/order.go
+++ b/src/cmd/compile/internal/gc/order.go
@@ -319,9 +319,80 @@ func (o *Order) cleanTemp(top ordermarker) {
// stmtList orders each of the statements in the list.
func (o *Order) stmtList(l Nodes) {
- for _, n := range l.Slice() {
- o.stmt(n)
+ s := l.Slice()
+ for i := range s {
+ orderMakeSliceCopy(s[i:])
+ o.stmt(s[i])
+ }
+}
+
+// orderMakeSliceCopy matches the pattern:
+// m = OMAKESLICE([]T, x); OCOPY(m, s)
+// and rewrites it to:
+// m = OMAKESLICECOPY([]T, x, s); nil
+func orderMakeSliceCopy(s []*Node) {
+ const go115makeslicecopy = true
+ if !go115makeslicecopy {
+ return
}
+
+ if Debug['N'] != 0 || instrumenting {
+ return
+ }
+
+ if len(s) < 2 {
+ return
+ }
+
+ asn := s[0]
+ copyn := s[1]
+
+ if asn == nil || asn.Op != OAS {
+ return
+ }
+ if asn.Left.Op != ONAME {
+ return
+ }
+ if asn.Left.isBlank() {
+ return
+ }
+ maken := asn.Right
+ if maken == nil || maken.Op != OMAKESLICE {
+ return
+ }
+ if maken.Esc == EscNone {
+ return
+ }
+ if maken.Left == nil || maken.Right != nil {
+ return
+ }
+ if copyn.Op != OCOPY {
+ return
+ }
+ if copyn.Left.Op != ONAME {
+ return
+ }
+ if asn.Left.Sym != copyn.Left.Sym {
+ return
+ }
+ if copyn.Right.Op != ONAME {
+ return
+ }
+
+ if copyn.Left.Sym == copyn.Right.Sym {
+ return
+ }
+
+ maken.Op = OMAKESLICECOPY
+ maken.Right = copyn.Right
+ // Set bounded when m = OMAKESLICE([]T, len(s)); OCOPY(m, s)
+ maken.SetBounded(maken.Left.Op == OLEN && samesafeexpr(maken.Left.Left, copyn.Right))
+
+ maken = typecheck(maken, ctxExpr)
+
+ s[1] = nil // remove separate copy call
+
+ return
}
// edge inserts coverage instrumentation for libfuzzer.
@@ -1150,6 +1221,7 @@ func (o *Order) expr(n, lhs *Node) *Node {
OMAKECHAN,
OMAKEMAP,
OMAKESLICE,
+ OMAKESLICECOPY,
ONEW,
OREAL,
ORECOVER,
diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go
index 6ccd0b8d94..74654c86bc 100644
--- a/src/cmd/compile/internal/gc/pgen.go
+++ b/src/cmd/compile/internal/gc/pgen.go
@@ -271,7 +271,7 @@ func compile(fn *Node) {
}
}
- if compilenow() {
+ if compilenow(fn) {
compileSSA(fn, 0)
} else {
compilequeue = append(compilequeue, fn)
@@ -282,10 +282,31 @@ func compile(fn *Node) {
// If functions are not compiled immediately,
// they are enqueued in compilequeue,
// which is drained by compileFunctions.
-func compilenow() bool {
+func compilenow(fn *Node) bool {
+ // Issue 38068: if this function is a method AND an inline
+ // candidate AND was not inlined (yet), put it onto the compile
+ // queue instead of compiling it immediately. This is in case we
+ // wind up inlining it into a method wrapper that is generated by
+ // compiling a function later on in the xtop list.
+ if fn.IsMethod() && isInlinableButNotInlined(fn) {
+ return false
+ }
return nBackendWorkers == 1 && Debug_compilelater == 0
}
+// isInlinableButNotInlined returns true if 'fn' was marked as an
+// inline candidate but then never inlined (presumably because we
+// found no call sites).
+func isInlinableButNotInlined(fn *Node) bool {
+ if fn.Func.Nname.Func.Inl == nil {
+ return false
+ }
+ if fn.Sym == nil {
+ return true
+ }
+ return !fn.Sym.Linksym().WasInlined()
+}
+
const maxStackSize = 1 << 30
// compileSSA builds an SSA backend function,
diff --git a/src/cmd/compile/internal/gc/plive.go b/src/cmd/compile/internal/gc/plive.go
index a4c051bda6..7e1c0c1a95 100644
--- a/src/cmd/compile/internal/gc/plive.go
+++ b/src/cmd/compile/internal/gc/plive.go
@@ -680,8 +680,9 @@ func (lv *Liveness) pointerMap(liveout bvec, vars []*Node, args, locals bvec) {
}
}
-// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
-func (lv *Liveness) markUnsafePoints() {
+// allUnsafe indicates that all points in this function are
+// unsafe-points.
+func allUnsafe(f *ssa.Func) bool {
// The runtime assumes the only safe-points are function
// prologues (because that's how it used to be). We could and
// should improve that, but for now keep consider all points
@@ -691,7 +692,12 @@ func (lv *Liveness) markUnsafePoints() {
// go:nosplit functions are similar. Since safe points used to
// be coupled with stack checks, go:nosplit often actually
// means "no safe points in this function".
- if compiling_runtime || lv.f.NoSplit {
+ return compiling_runtime || f.NoSplit
+}
+
+// markUnsafePoints finds unsafe points and computes lv.unsafePoints.
+func (lv *Liveness) markUnsafePoints() {
+ if allUnsafe(lv.f) {
// No complex analysis necessary.
lv.allUnsafe = true
return
@@ -1249,7 +1255,7 @@ func (lv *Liveness) compact(b *ssa.Block) {
if go115ReduceLiveness {
hasStackMap := lv.hasStackMap(v)
isUnsafePoint := lv.allUnsafe || lv.unsafePoints.Get(int32(v.ID))
- idx := LivenessIndex{StackMapDontCare, 0, isUnsafePoint}
+ idx := LivenessIndex{StackMapDontCare, StackMapDontCare, isUnsafePoint}
if hasStackMap {
idx.stackMapIndex = lv.stackMapSet.add(lv.livevars[pos].vars)
pos++
diff --git a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
index 59d1edb9e8..8101e44079 100644
--- a/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
+++ b/src/cmd/compile/internal/gc/reproduciblebuilds_test.go
@@ -60,3 +60,53 @@ func TestReproducibleBuilds(t *testing.T) {
})
}
}
+
+func TestIssue38068(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+ t.Parallel()
+
+ // Compile a small package with and without the concurrent
+ // backend, then check to make sure that the resulting archives
+ // are identical. Note: this uses "go tool compile" instead of
+ // "go build" since the latter will generate differnent build IDs
+ // if it sees different command line flags.
+ scenarios := []struct {
+ tag string
+ args string
+ libpath string
+ }{
+ {tag: "serial", args: "-c=1"},
+ {tag: "concurrent", args: "-c=2"}}
+
+ tmpdir, err := ioutil.TempDir("", "TestIssue38068")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ src := filepath.Join("testdata", "reproducible", "issue38068.go")
+ for i := range scenarios {
+ s := &scenarios[i]
+ s.libpath = filepath.Join(tmpdir, s.tag+".a")
+ // Note: use of "-p" required in order for DWARF to be generated.
+ cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%v: %v:\n%s", cmd.Args, err, out)
+ }
+ }
+
+ readBytes := func(fn string) []byte {
+ payload, err := ioutil.ReadFile(fn)
+ if err != nil {
+ t.Fatalf("failed to read executable '%s': %v", fn, err)
+ }
+ return payload
+ }
+
+ b1 := readBytes(scenarios[0].libpath)
+ b2 := readBytes(scenarios[1].libpath)
+ if !bytes.Equal(b1, b2) {
+ t.Fatalf("concurrent and serial builds produced different output")
+ }
+}
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 70f6dd6e18..d4d23a2956 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -6010,8 +6010,8 @@ func genssa(f *ssa.Func, pp *Progs) {
// for an empty block this will be used for its control
// instruction. We won't use the actual liveness map on a
// control instruction. Just mark it something that is
- // preemptible.
- s.pp.nextLive = LivenessIndex{-1, -1, false}
+ // preemptible, unless this function is "all unsafe".
+ s.pp.nextLive = LivenessIndex{-1, -1, allUnsafe(f)}
// Emit values in block
thearch.SSAMarkMoves(&s, b)
@@ -6313,34 +6313,39 @@ func defframe(s *SSAGenState, e *ssafn) {
thearch.ZeroRange(pp, p, frame+lo, hi-lo, &state)
}
-type FloatingEQNEJump struct {
+// For generating consecutive jump instructions to model a specific branching
+type IndexJump struct {
Jump obj.As
Index int
}
-func (s *SSAGenState) oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump) {
- p := s.Prog(jumps.Jump)
- p.To.Type = obj.TYPE_BRANCH
+func (s *SSAGenState) oneJump(b *ssa.Block, jump *IndexJump) {
+ p := s.Br(jump.Jump, b.Succs[jump.Index].Block())
p.Pos = b.Pos
- to := jumps.Index
- s.Branches = append(s.Branches, Branch{p, b.Succs[to].Block()})
}
-func (s *SSAGenState) FPJump(b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
+// CombJump generates combinational instructions (2 at present) for a block jump,
+// thereby the behaviour of non-standard condition codes could be simulated
+func (s *SSAGenState) CombJump(b, next *ssa.Block, jumps *[2][2]IndexJump) {
switch next {
case b.Succs[0].Block():
- s.oneFPJump(b, &jumps[0][0])
- s.oneFPJump(b, &jumps[0][1])
+ s.oneJump(b, &jumps[0][0])
+ s.oneJump(b, &jumps[0][1])
case b.Succs[1].Block():
- s.oneFPJump(b, &jumps[1][0])
- s.oneFPJump(b, &jumps[1][1])
+ s.oneJump(b, &jumps[1][0])
+ s.oneJump(b, &jumps[1][1])
default:
- s.oneFPJump(b, &jumps[1][0])
- s.oneFPJump(b, &jumps[1][1])
- q := s.Prog(obj.AJMP)
+ var q *obj.Prog
+ if b.Likely != ssa.BranchUnlikely {
+ s.oneJump(b, &jumps[1][0])
+ s.oneJump(b, &jumps[1][1])
+ q = s.Br(obj.AJMP, b.Succs[1].Block())
+ } else {
+ s.oneJump(b, &jumps[0][0])
+ s.oneJump(b, &jumps[0][1])
+ q = s.Br(obj.AJMP, b.Succs[0].Block())
+ }
q.Pos = b.Pos
- q.To.Type = obj.TYPE_BRANCH
- s.Branches = append(s.Branches, Branch{q, b.Succs[1].Block()})
}
}
diff --git a/src/cmd/compile/internal/gc/subr.go b/src/cmd/compile/internal/gc/subr.go
index 2bbc5e4ae1..9362c74288 100644
--- a/src/cmd/compile/internal/gc/subr.go
+++ b/src/cmd/compile/internal/gc/subr.go
@@ -60,9 +60,15 @@ func adderrorname(n *Node) {
}
func adderr(pos src.XPos, format string, args ...interface{}) {
+ msg := fmt.Sprintf(format, args...)
+ // Only add the position if know the position.
+ // See issue golang.org/issue/11361.
+ if pos.IsKnown() {
+ msg = fmt.Sprintf("%v: %s", linestr(pos), msg)
+ }
errors = append(errors, Error{
pos: pos,
- msg: fmt.Sprintf("%v: %s\n", linestr(pos), fmt.Sprintf(format, args...)),
+ msg: msg + "\n",
})
}
diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go
index a9bd723351..b658410c53 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -208,12 +208,16 @@ func (n *Node) MarkNonNil() {
// SetBounded indicates whether operation n does not need safety checks.
// When n is an index or slice operation, n does not need bounds checks.
// When n is a dereferencing operation, n does not need nil checks.
+// When n is a makeslice+copy operation, n does not need length and cap checks.
func (n *Node) SetBounded(b bool) {
switch n.Op {
case OINDEX, OSLICE, OSLICEARR, OSLICE3, OSLICE3ARR, OSLICESTR:
// No bounds checks needed.
case ODOTPTR, ODEREF:
// No nil check needed.
+ case OMAKESLICECOPY:
+ // No length and cap checks needed
+ // since new slice and copied over slice data have same length.
default:
Fatalf("SetBounded(%v)", n)
}
@@ -714,30 +718,38 @@ const (
ODCLCONST // const pi = 3.14
ODCLTYPE // type Int int or type Int = int
- ODELETE // delete(Left, Right)
- ODOT // Left.Sym (Left is of struct type)
- ODOTPTR // Left.Sym (Left is of pointer to struct type)
- ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
- ODOTINTER // Left.Sym (Left is interface, Right is method name)
- OXDOT // Left.Sym (before rewrite to one of the preceding)
- ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
- ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
- OEQ // Left == Right
- ONE // Left != Right
- OLT // Left < Right
- OLE // Left <= Right
- OGE // Left >= Right
- OGT // Left > Right
- ODEREF // *Left
- OINDEX // Left[Right] (index of array or slice)
- OINDEXMAP // Left[Right] (index of map)
- OKEY // Left:Right (key:value in struct/array/map literal)
- OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
- OLEN // len(Left)
- OMAKE // make(List) (before type checking converts to one of the following)
- OMAKECHAN // make(Type, Left) (type is chan)
- OMAKEMAP // make(Type, Left) (type is map)
- OMAKESLICE // make(Type, Left, Right) (type is slice)
+ ODELETE // delete(Left, Right)
+ ODOT // Left.Sym (Left is of struct type)
+ ODOTPTR // Left.Sym (Left is of pointer to struct type)
+ ODOTMETH // Left.Sym (Left is non-interface, Right is method name)
+ ODOTINTER // Left.Sym (Left is interface, Right is method name)
+ OXDOT // Left.Sym (before rewrite to one of the preceding)
+ ODOTTYPE // Left.Right or Left.Type (.Right during parsing, .Type once resolved); after walk, .Right contains address of interface type descriptor and .Right.Right contains address of concrete type descriptor
+ ODOTTYPE2 // Left.Right or Left.Type (.Right during parsing, .Type once resolved; on rhs of OAS2DOTTYPE); after walk, .Right contains address of interface type descriptor
+ OEQ // Left == Right
+ ONE // Left != Right
+ OLT // Left < Right
+ OLE // Left <= Right
+ OGE // Left >= Right
+ OGT // Left > Right
+ ODEREF // *Left
+ OINDEX // Left[Right] (index of array or slice)
+ OINDEXMAP // Left[Right] (index of map)
+ OKEY // Left:Right (key:value in struct/array/map literal)
+ OSTRUCTKEY // Sym:Left (key:value in struct literal, after type checking)
+ OLEN // len(Left)
+ OMAKE // make(List) (before type checking converts to one of the following)
+ OMAKECHAN // make(Type, Left) (type is chan)
+ OMAKEMAP // make(Type, Left) (type is map)
+ OMAKESLICE // make(Type, Left, Right) (type is slice)
+ OMAKESLICECOPY // makeslicecopy(Type, Left, Right) (type is slice; Left is length and Right is the copied from slice)
+ // OMAKESLICECOPY is created by the order pass and corresponds to:
+ // s = make(Type, Left); copy(s, Right)
+ //
+ // Bounded can be set on the node when Left == len(Right) is known at compile time.
+ //
+ // This node is created so the walk pass can optimize this pattern which would
+ // otherwise be hard to detect after the order pass.
OMUL // Left * Right
ODIV // Left / Right
OMOD // Left % Right
diff --git a/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go b/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
new file mode 100644
index 0000000000..db5ca7dcbe
--- /dev/null
+++ b/src/cmd/compile/internal/gc/testdata/reproducible/issue38068.go
@@ -0,0 +1,70 @@
+// Copyright 2020 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 issue38068
+
+// A type with a couple of inlinable, non-pointer-receiver methods
+// that have params and local variables.
+type A struct {
+ s string
+ next *A
+ prev *A
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) double(x string, y int) string {
+ if y == 191 {
+ a.s = ""
+ }
+ q := a.s + "a"
+ r := a.s + "b"
+ return q + r
+}
+
+// Inlinable, value-received method with locals and parms.
+func (a A) triple(x string, y int) string {
+ q := a.s
+ if y == 998877 {
+ a.s = x
+ }
+ r := a.s + a.s
+ return q + r
+}
+
+type methods struct {
+ m1 func(a *A, x string, y int) string
+ m2 func(a *A, x string, y int) string
+}
+
+// Now a function that makes references to the methods via pointers,
+// which should trigger the wrapper generation.
+func P(a *A, ms *methods) {
+ if a != nil {
+ defer func() { println("done") }()
+ }
+ println(ms.m1(a, "a", 2))
+ println(ms.m2(a, "b", 3))
+}
+
+func G(x *A, n int) {
+ if n <= 0 {
+ println(n)
+ return
+ }
+ // Address-taken local of type A, which will insure that the
+ // compiler's dtypesym() routine will create a method wrapper.
+ var a, b A
+ a.next = x
+ a.prev = &b
+ x = &a
+ G(x, n-2)
+}
+
+var M methods
+
+func F() {
+ M.m1 = (*A).double
+ M.m2 = (*A).triple
+ G(nil, 100)
+}
diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go
index 6e04908b46..dec4b96fc4 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -1149,6 +1149,49 @@ func typecheck1(n *Node, top int) (res *Node) {
n.List.SetFirst(l)
n.List.SetSecond(c)
+ case OMAKESLICECOPY:
+ // Errors here are Fatalf instead of yyerror because only the compiler
+ // can construct an OMAKESLICECOPY node.
+ // Components used in OMAKESCLICECOPY that are supplied by parsed source code
+ // have already been typechecked in OMAKE and OCOPY earlier.
+ ok |= ctxExpr
+
+ t := n.Type
+
+ if t == nil {
+ Fatalf("no type specified for OMAKESLICECOPY")
+ }
+
+ if !t.IsSlice() {
+ Fatalf("invalid type %v for OMAKESLICECOPY", n.Type)
+ }
+
+ if n.Left == nil {
+ Fatalf("missing len argument for OMAKESLICECOPY")
+ }
+
+ if n.Right == nil {
+ Fatalf("missing slice argument to copy for OMAKESLICECOPY")
+ }
+
+ n.Left = typecheck(n.Left, ctxExpr)
+ n.Right = typecheck(n.Right, ctxExpr)
+
+ n.Left = defaultlit(n.Left, types.Types[TINT])
+
+ if !n.Left.Type.IsInteger() && n.Type.Etype != TIDEAL {
+ yyerror("non-integer len argument in OMAKESLICECOPY")
+ }
+
+ if Isconst(n.Left, CTINT) {
+ if n.Left.Val().U.(*Mpint).Cmp(maxintval[TINT]) > 0 {
+ Fatalf("len for OMAKESLICECOPY too large")
+ }
+ if n.Left.Int64() < 0 {
+ Fatalf("len for OMAKESLICECOPY must be non-negative")
+ }
+ }
+
case OSLICE, OSLICE3:
ok |= ctxExpr
n.Left = typecheck(n.Left, ctxExpr)
@@ -2924,6 +2967,8 @@ func typecheckcomplit(n *Node) (res *Node) {
if ci := lookdot1(nil, l.Sym, t, t.Fields(), 2); ci != nil { // Case-insensitive lookup.
if visible(ci.Sym) {
yyerror("unknown field '%v' in struct literal of type %v (but does have %v)", l.Sym, t, ci.Sym)
+ } else if nonexported(l.Sym) && l.Sym.Name == ci.Sym.Name { // Ensure exactness before the suggestion.
+ yyerror("cannot refer to unexported field '%v' in struct literal of type %v", l.Sym, t)
} else {
yyerror("unknown field '%v' in struct literal of type %v", l.Sym, t)
}
@@ -3027,6 +3072,11 @@ func visible(sym *types.Sym) bool {
return sym != nil && (types.IsExported(sym.Name) || sym.Pkg == localpkg)
}
+// nonexported reports whether sym is an unexported field.
+func nonexported(sym *types.Sym) bool {
+ return sym != nil && !types.IsExported(sym.Name)
+}
+
// 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 84ba528bc9..1e6d913ae6 100644
--- a/src/cmd/compile/internal/gc/walk.go
+++ b/src/cmd/compile/internal/gc/walk.go
@@ -1390,6 +1390,63 @@ opswitch:
n = m
}
+ case OMAKESLICECOPY:
+ if n.Esc == EscNone {
+ Fatalf("OMAKESLICECOPY with EscNone: %v", n)
+ }
+
+ t := n.Type
+ if t.Elem().NotInHeap() {
+ Fatalf("%v is go:notinheap; heap allocation disallowed", t.Elem())
+ }
+
+ length := conv(n.Left, types.Types[TINT])
+ copylen := nod(OLEN, n.Right, nil)
+ copyptr := nod(OSPTR, n.Right, nil)
+
+ if !types.Haspointers(t.Elem()) && n.Bounded() {
+ // When len(to)==len(from) and elements have no pointers:
+ // replace make+copy with runtime.mallocgc+runtime.memmove.
+
+ // We do not check for overflow of len(to)*elem.Width here
+ // since len(from) is an existing checked slice capacity
+ // with same elem.Width for the from slice.
+ size := nod(OMUL, conv(length, types.Types[TUINTPTR]), conv(nodintconst(t.Elem().Width), types.Types[TUINTPTR]))
+
+ // instantiate mallocgc(size uintptr, typ *byte, needszero bool) unsafe.Pointer
+ fn := syslook("mallocgc")
+ sh := nod(OSLICEHEADER, nil, nil)
+ sh.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, size, nodnil(), nodbool(false))
+ sh.Left.MarkNonNil()
+ sh.List.Set2(length, length)
+ sh.Type = t
+
+ s := temp(t)
+ r := typecheck(nod(OAS, s, sh), ctxStmt)
+ r = walkexpr(r, init)
+ init.Append(r)
+
+ // instantiate memmove(to *any, frm *any, size uintptr)
+ fn = syslook("memmove")
+ fn = substArgTypes(fn, t.Elem(), t.Elem())
+ ncopy := mkcall1(fn, nil, init, nod(OSPTR, s, nil), copyptr, size)
+ ncopy = typecheck(ncopy, ctxStmt)
+ ncopy = walkexpr(ncopy, init)
+ init.Append(ncopy)
+
+ n = s
+ } else { // Replace make+copy with runtime.makeslicecopy.
+ // instantiate makeslicecopy(typ *byte, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer
+ fn := syslook("makeslicecopy")
+ s := nod(OSLICEHEADER, nil, nil)
+ s.Left = mkcall1(fn, types.Types[TUNSAFEPTR], init, typename(t.Elem()), length, copylen, conv(copyptr, types.Types[TUNSAFEPTR]))
+ s.Left.MarkNonNil()
+ s.List.Set2(length, length)
+ s.Type = t
+ n = typecheck(s, ctxExpr)
+ n = walkexpr(n, init)
+ }
+
case ORUNESTR:
a := nodnil()
if n.Esc == EscNone {
@@ -3772,6 +3829,9 @@ func candiscard(n *Node) bool {
// Difficult to tell what sizes are okay.
case OMAKESLICE:
return false
+
+ case OMAKESLICECOPY:
+ return false
}
if !candiscard(n.Left) || !candiscard(n.Right) || !candiscardlist(n.Ninit) || !candiscardlist(n.Nbody) || !candiscardlist(n.List) || !candiscardlist(n.Rlist) {
diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go
index 20ca28a54b..98e1b79334 100644
--- a/src/cmd/compile/internal/ssa/check.go
+++ b/src/cmd/compile/internal/ssa/check.go
@@ -185,6 +185,11 @@ func checkFunc(f *Func) {
f.Fatalf("bad type %T for S390XRotateParams in %v", v.Aux, v)
}
canHaveAux = true
+ case auxFlagConstant:
+ if v.AuxInt < 0 || v.AuxInt > 15 {
+ f.Fatalf("bad FlagConstant AuxInt value for %v", v)
+ }
+ canHaveAuxInt = true
default:
f.Fatalf("unknown aux type for %s", v.Op)
}
diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go
index 2dbe9cf405..dbdd027716 100644
--- a/src/cmd/compile/internal/ssa/compile.go
+++ b/src/cmd/compile/internal/ssa/compile.go
@@ -451,6 +451,7 @@ var passes = [...]pass{
{name: "lowered deadcode for cse", fn: deadcode}, // deadcode immediately before CSE avoids CSE making dead values live again
{name: "lowered cse", fn: cse},
{name: "elim unread autos", fn: elimUnreadAutos},
+ {name: "tighten tuple selectors", fn: tightenTupleSelectors, required: true},
{name: "lowered deadcode", fn: deadcode, required: true},
{name: "checkLower", fn: checkLower, required: true},
{name: "late phielim", fn: phielim},
@@ -509,6 +510,8 @@ var passOrder = [...]constraint{
{"decompose builtin", "late opt"},
// decompose builtin is the last pass that may introduce new float ops, so run softfloat after it
{"decompose builtin", "softfloat"},
+ // tuple selectors must be tightened to generators and de-duplicated before scheduling
+ {"tighten tuple selectors", "schedule"},
// remove critical edges before phi tighten, so that phi args get better placement
{"critical", "phi tighten"},
// don't layout blocks until critical edges have been removed
diff --git a/src/cmd/compile/internal/ssa/cse.go b/src/cmd/compile/internal/ssa/cse.go
index 15dfe6d795..3b4f2be37e 100644
--- a/src/cmd/compile/internal/ssa/cse.go
+++ b/src/cmd/compile/internal/ssa/cse.go
@@ -190,43 +190,6 @@ func cse(f *Func) {
}
}
- // if we rewrite a tuple generator to a new one in a different block,
- // copy its selectors to the new generator's block, so tuple generator
- // and selectors stay together.
- // be careful not to copy same selectors more than once (issue 16741).
- copiedSelects := make(map[ID][]*Value)
- for _, b := range f.Blocks {
- out:
- for _, v := range b.Values {
- // New values are created when selectors are copied to
- // a new block. We can safely ignore those new values,
- // since they have already been copied (issue 17918).
- if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
- continue
- }
- if v.Op != OpSelect0 && v.Op != OpSelect1 {
- continue
- }
- if !v.Args[0].Type.IsTuple() {
- f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
- }
- t := rewrite[v.Args[0].ID]
- if t != nil && t.Block != b {
- // v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
- for _, c := range copiedSelects[t.ID] {
- if v.Op == c.Op {
- // an equivalent selector is already copied
- rewrite[v.ID] = c
- continue out
- }
- }
- c := v.copyInto(t.Block)
- rewrite[v.ID] = c
- copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
- }
- }
- }
-
rewrites := int64(0)
// Apply substitutions
@@ -259,6 +222,7 @@ func cse(f *Func) {
}
}
}
+
if f.pass.stats > 0 {
f.LogStat("CSE REWRITES", rewrites)
}
diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go
index 88af7a6f4a..0664013b39 100644
--- a/src/cmd/compile/internal/ssa/deadstore.go
+++ b/src/cmd/compile/internal/ssa/deadstore.go
@@ -73,9 +73,11 @@ func dse(f *Func) {
}
// Walk backwards looking for dead stores. Keep track of shadowed addresses.
- // An "address" is an SSA Value which encodes both the address and size of
- // the write. This code will not remove dead stores to the same address
- // of different types.
+ // A "shadowed address" is a pointer and a size describing a memory region that
+ // is known to be written. We keep track of shadowed addresses in the shadowed
+ // map, mapping the ID of the address to the size of the shadowed region.
+ // Since we're walking backwards, writes to a shadowed region are useless,
+ // as they will be immediately overwritten.
shadowed.clear()
v := last
@@ -93,17 +95,13 @@ func dse(f *Func) {
sz = v.AuxInt
}
if shadowedSize := int64(shadowed.get(v.Args[0].ID)); shadowedSize != -1 && shadowedSize >= sz {
- // Modify store into a copy
+ // Modify the store/zero into a copy of the memory state,
+ // effectively eliding the store operation.
if v.Op == OpStore {
// store addr value mem
v.SetArgs1(v.Args[2])
} else {
// zero addr mem
- typesz := v.Args[0].Type.Elem().Size()
- if sz != typesz {
- f.Fatalf("mismatched zero/store sizes: %d and %d [%s]",
- sz, typesz, v.LongString())
- }
v.SetArgs1(v.Args[1])
}
v.Aux = nil
diff --git a/src/cmd/compile/internal/ssa/debug_test.go b/src/cmd/compile/internal/ssa/debug_test.go
index d68cb1ccc0..3346312542 100644
--- a/src/cmd/compile/internal/ssa/debug_test.go
+++ b/src/cmd/compile/internal/ssa/debug_test.go
@@ -49,11 +49,11 @@ var gogcflags = os.Getenv("GO_GCFLAGS")
// optimizedLibs usually means "not running in a noopt test builder".
var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gogcflags, "-l"))
-// TestNexting go-builds a file, then uses a debugger (default gdb, optionally delve)
+// TestNexting go-builds a file, then uses a debugger (default delve, optionally gdb)
// to next through the generated executable, recording each line landed at, and
// then compares those lines with reference file(s).
// Flag -u updates the reference file(s).
-// Flag -d changes the debugger to delve (and uses delve-specific reference files)
+// Flag -g changes the debugger to gdb (and uses gdb-specific reference files)
// Flag -v is ever-so-slightly verbose.
// Flag -n is for dry-run, and prints the shell and first debug commands.
//
@@ -83,9 +83,9 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
// to indicate normalization of Strings, (hex) addresses, and numbers.
// "O" is an explicit indication that we expect it to be optimized out.
// For example:
-/*
- if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
-*/
+//
+// if len(os.Args) > 1 { //gdb-dbg=(hist/A,cannedInput/A) //dlv-dbg=(hist/A,cannedInput/A)
+//
// TODO: not implemented for Delve yet, but this is the plan
//
// After a compiler change that causes a difference in the debug behavior, check
@@ -93,7 +93,7 @@ var optimizedLibs = (!strings.Contains(gogcflags, "-N") && !strings.Contains(gog
// go test debug_test.go -args -u
// (for Delve)
// go test debug_test.go -args -u -d
-
+//
func TestNexting(t *testing.T) {
testenv.SkipFlaky(t, 37404)
@@ -110,7 +110,13 @@ func TestNexting(t *testing.T) {
// Various architectures tend to differ slightly sometimes, and keeping them
// all in sync is a pain for people who don't have them all at hand,
// so limit testing to amd64 (for now)
- skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64"
+ skipReasons += "not run when testing gdb (-g) unless forced (-f) or linux-amd64; "
+ }
+
+ if !*useGdb && !*force && testenv.Builder() == "linux-386-longtest" {
+ // The latest version of Delve does support linux/386. However, the version currently
+ // installed in the linux-386-longtest builder does not. See golang.org/issue/39309.
+ skipReasons += "not run when testing delve on linux-386-longtest builder unless forced (-f); "
}
if *useGdb {
diff --git a/src/cmd/compile/internal/ssa/flags_amd64_test.s b/src/cmd/compile/internal/ssa/flags_amd64_test.s
new file mode 100644
index 0000000000..8bd87019af
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/flags_amd64_test.s
@@ -0,0 +1,31 @@
+// Copyright 2020 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 amd64
+
+#include "textflag.h"
+
+TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
+ MOVQ x+0(FP), AX
+ ADDQ y+8(FP), AX
+ PUSHFQ
+ POPQ AX
+ MOVQ AX, ret+16(FP)
+ RET
+
+TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
+ MOVQ x+0(FP), AX
+ SUBQ y+8(FP), AX
+ PUSHFQ
+ POPQ AX
+ MOVQ AX, ret+16(FP)
+ RET
+
+TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
+ MOVQ x+0(FP), AX
+ ANDQ y+8(FP), AX
+ PUSHFQ
+ POPQ AX
+ MOVQ AX, ret+16(FP)
+ RET
diff --git a/src/cmd/compile/internal/ssa/flags_arm64_test.s b/src/cmd/compile/internal/ssa/flags_arm64_test.s
new file mode 100644
index 0000000000..f201bcc994
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/flags_arm64_test.s
@@ -0,0 +1,32 @@
+// Copyright 2020 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 arm64
+
+#include "textflag.h"
+
+TEXT ·asmAddFlags(SB),NOSPLIT,$0-24
+ MOVD x+0(FP), R0
+ MOVD y+8(FP), R1
+ CMN R0, R1
+ WORD $0xd53b4200 // MOVD NZCV, R0
+ MOVD R0, ret+16(FP)
+ RET
+
+TEXT ·asmSubFlags(SB),NOSPLIT,$0-24
+ MOVD x+0(FP), R0
+ MOVD y+8(FP), R1
+ CMP R1, R0
+ WORD $0xd53b4200 // MOVD NZCV, R0
+ MOVD R0, ret+16(FP)
+ RET
+
+TEXT ·asmAndFlags(SB),NOSPLIT,$0-24
+ MOVD x+0(FP), R0
+ MOVD y+8(FP), R1
+ TST R1, R0
+ WORD $0xd53b4200 // MOVD NZCV, R0
+ BIC $0x30000000, R0 // clear C, V bits, as TST does not change those flags
+ MOVD R0, ret+16(FP)
+ RET
diff --git a/src/cmd/compile/internal/ssa/flags_test.go b/src/cmd/compile/internal/ssa/flags_test.go
new file mode 100644
index 0000000000..d64abf652c
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/flags_test.go
@@ -0,0 +1,108 @@
+// Copyright 2020 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 amd64 arm64
+
+package ssa
+
+// This file tests the functions addFlags64 and subFlags64 by comparing their
+// results to what the chip calculates.
+
+import (
+ "runtime"
+ "testing"
+)
+
+func TestAddFlagsNative(t *testing.T) {
+ var numbers = []int64{
+ 1, 0, -1,
+ 2, -2,
+ 1<<63 - 1, -1 << 63,
+ }
+ coverage := map[flagConstant]bool{}
+ for _, x := range numbers {
+ for _, y := range numbers {
+ a := addFlags64(x, y)
+ b := flagRegister2flagConstant(asmAddFlags(x, y), false)
+ if a != b {
+ t.Errorf("asmAdd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
+ }
+ coverage[a] = true
+ }
+ }
+ if len(coverage) != 9 { // TODO: can we cover all outputs?
+ t.Errorf("coverage too small, got %d want 9", len(coverage))
+ }
+}
+
+func TestSubFlagsNative(t *testing.T) {
+ var numbers = []int64{
+ 1, 0, -1,
+ 2, -2,
+ 1<<63 - 1, -1 << 63,
+ }
+ coverage := map[flagConstant]bool{}
+ for _, x := range numbers {
+ for _, y := range numbers {
+ a := subFlags64(x, y)
+ b := flagRegister2flagConstant(asmSubFlags(x, y), true)
+ if a != b {
+ t.Errorf("asmSub diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
+ }
+ coverage[a] = true
+ }
+ }
+ if len(coverage) != 7 { // TODO: can we cover all outputs?
+ t.Errorf("coverage too small, got %d want 7", len(coverage))
+ }
+}
+
+func TestAndFlagsNative(t *testing.T) {
+ var numbers = []int64{
+ 1, 0, -1,
+ 2, -2,
+ 1<<63 - 1, -1 << 63,
+ }
+ coverage := map[flagConstant]bool{}
+ for _, x := range numbers {
+ for _, y := range numbers {
+ a := logicFlags64(x & y)
+ b := flagRegister2flagConstant(asmAndFlags(x, y), false)
+ if a != b {
+ t.Errorf("asmAnd diff: x=%x y=%x got=%s want=%s\n", x, y, a, b)
+ }
+ coverage[a] = true
+ }
+ }
+ if len(coverage) != 3 {
+ t.Errorf("coverage too small, got %d want 3", len(coverage))
+ }
+}
+
+func asmAddFlags(x, y int64) int
+func asmSubFlags(x, y int64) int
+func asmAndFlags(x, y int64) int
+
+func flagRegister2flagConstant(x int, sub bool) flagConstant {
+ var fcb flagConstantBuilder
+ switch runtime.GOARCH {
+ case "amd64":
+ fcb.Z = x>>6&1 != 0
+ fcb.N = x>>7&1 != 0
+ fcb.C = x>>0&1 != 0
+ if sub {
+ // Convert from amd64-sense to arm-sense
+ fcb.C = !fcb.C
+ }
+ fcb.V = x>>11&1 != 0
+ case "arm64":
+ fcb.Z = x>>30&1 != 0
+ fcb.N = x>>31&1 != 0
+ fcb.C = x>>29&1 != 0
+ fcb.V = x>>28&1 != 0
+ default:
+ panic("unsupported architecture: " + runtime.GOARCH)
+ }
+ return fcb.encode()
+}
diff --git a/src/cmd/compile/internal/ssa/gen/ARM.rules b/src/cmd/compile/internal/ssa/gen/ARM.rules
index a8cea68c5f..ab8bd0e81e 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM.rules
@@ -609,89 +609,59 @@
(Select1 (CALLudiv x (MOVWconst [c]))) && isPowerOfTwo(c) -> (ANDconst [c-1] x)
// constant comparisons
-(CMPconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
-(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
-(CMPconst (MOVWconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
-(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
-(CMPconst (MOVWconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
-(CMNconst (MOVWconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
-(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
-(CMNconst (MOVWconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
-(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
-(CMNconst (MOVWconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
-(TSTconst (MOVWconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
-(TSTconst (MOVWconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
-(TSTconst (MOVWconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
-(TEQconst (MOVWconst [x]) [y]) && int32(x^y)==0 -> (FlagEQ)
-(TEQconst (MOVWconst [x]) [y]) && int32(x^y)<0 -> (FlagLT_UGT)
-(TEQconst (MOVWconst [x]) [y]) && int32(x^y)>0 -> (FlagGT_UGT)
+(CMPconst (MOVWconst [x]) [y]) => (FlagConstant [subFlags32(x,y)])
+(CMNconst (MOVWconst [x]) [y]) => (FlagConstant [addFlags32(x,y)])
+(TSTconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x&y)])
+(TEQconst (MOVWconst [x]) [y]) => (FlagConstant [logicFlags32(x^y)])
// other known comparisons
-(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
-(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
-(CMPconst (ANDconst _ [m]) [n]) && 0 <= int32(m) && int32(m) < int32(n) -> (FlagLT_ULT)
-(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT_ULT)
+(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags32(0, 1)])
+(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags32(0, 1)])
+(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags32(0, 1)])
+(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) => (FlagConstant [subFlags32(0, 1)])
// absorb flag constants into branches
-(EQ (FlagEQ) yes no) -> (First yes no)
-(EQ (FlagLT_ULT) yes no) -> (First no yes)
-(EQ (FlagLT_UGT) yes no) -> (First no yes)
-(EQ (FlagGT_ULT) yes no) -> (First no yes)
-(EQ (FlagGT_UGT) yes no) -> (First no yes)
-
-(NE (FlagEQ) yes no) -> (First no yes)
-(NE (FlagLT_ULT) yes no) -> (First yes no)
-(NE (FlagLT_UGT) yes no) -> (First yes no)
-(NE (FlagGT_ULT) yes no) -> (First yes no)
-(NE (FlagGT_UGT) yes no) -> (First yes no)
-
-(LT (FlagEQ) yes no) -> (First no yes)
-(LT (FlagLT_ULT) yes no) -> (First yes no)
-(LT (FlagLT_UGT) yes no) -> (First yes no)
-(LT (FlagGT_ULT) yes no) -> (First no yes)
-(LT (FlagGT_UGT) yes no) -> (First no yes)
-
-(LE (FlagEQ) yes no) -> (First yes no)
-(LE (FlagLT_ULT) yes no) -> (First yes no)
-(LE (FlagLT_UGT) yes no) -> (First yes no)
-(LE (FlagGT_ULT) yes no) -> (First no yes)
-(LE (FlagGT_UGT) yes no) -> (First no yes)
-
-(GT (FlagEQ) yes no) -> (First no yes)
-(GT (FlagLT_ULT) yes no) -> (First no yes)
-(GT (FlagLT_UGT) yes no) -> (First no yes)
-(GT (FlagGT_ULT) yes no) -> (First yes no)
-(GT (FlagGT_UGT) yes no) -> (First yes no)
-
-(GE (FlagEQ) yes no) -> (First yes no)
-(GE (FlagLT_ULT) yes no) -> (First no yes)
-(GE (FlagLT_UGT) yes no) -> (First no yes)
-(GE (FlagGT_ULT) yes no) -> (First yes no)
-(GE (FlagGT_UGT) yes no) -> (First yes no)
-
-(ULT (FlagEQ) yes no) -> (First no yes)
-(ULT (FlagLT_ULT) yes no) -> (First yes no)
-(ULT (FlagLT_UGT) yes no) -> (First no yes)
-(ULT (FlagGT_ULT) yes no) -> (First yes no)
-(ULT (FlagGT_UGT) yes no) -> (First no yes)
-
-(ULE (FlagEQ) yes no) -> (First yes no)
-(ULE (FlagLT_ULT) yes no) -> (First yes no)
-(ULE (FlagLT_UGT) yes no) -> (First no yes)
-(ULE (FlagGT_ULT) yes no) -> (First yes no)
-(ULE (FlagGT_UGT) yes no) -> (First no yes)
-
-(UGT (FlagEQ) yes no) -> (First no yes)
-(UGT (FlagLT_ULT) yes no) -> (First no yes)
-(UGT (FlagLT_UGT) yes no) -> (First yes no)
-(UGT (FlagGT_ULT) yes no) -> (First no yes)
-(UGT (FlagGT_UGT) yes no) -> (First yes no)
-
-(UGE (FlagEQ) yes no) -> (First yes no)
-(UGE (FlagLT_ULT) yes no) -> (First no yes)
-(UGE (FlagLT_UGT) yes no) -> (First yes no)
-(UGE (FlagGT_ULT) yes no) -> (First no yes)
-(UGE (FlagGT_UGT) yes no) -> (First yes no)
+(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
+(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
+
+(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
+(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
+
+(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
+(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
+
+(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
+(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
+
+(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
+(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
+
+(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
+(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
+
+(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
+(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
+
+(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
+(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
+
+(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
+(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
+
+(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
+(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
+
+(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
+(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
+
+(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
+(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
+
+(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
+(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
+
+(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
+(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
// absorb InvertFlags into branches
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
@@ -704,67 +674,22 @@
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
+(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
+(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
+(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
+(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
// absorb flag constants into boolean values
-(Equal (FlagEQ)) -> (MOVWconst [1])
-(Equal (FlagLT_ULT)) -> (MOVWconst [0])
-(Equal (FlagLT_UGT)) -> (MOVWconst [0])
-(Equal (FlagGT_ULT)) -> (MOVWconst [0])
-(Equal (FlagGT_UGT)) -> (MOVWconst [0])
-
-(NotEqual (FlagEQ)) -> (MOVWconst [0])
-(NotEqual (FlagLT_ULT)) -> (MOVWconst [1])
-(NotEqual (FlagLT_UGT)) -> (MOVWconst [1])
-(NotEqual (FlagGT_ULT)) -> (MOVWconst [1])
-(NotEqual (FlagGT_UGT)) -> (MOVWconst [1])
-
-(LessThan (FlagEQ)) -> (MOVWconst [0])
-(LessThan (FlagLT_ULT)) -> (MOVWconst [1])
-(LessThan (FlagLT_UGT)) -> (MOVWconst [1])
-(LessThan (FlagGT_ULT)) -> (MOVWconst [0])
-(LessThan (FlagGT_UGT)) -> (MOVWconst [0])
-
-(LessThanU (FlagEQ)) -> (MOVWconst [0])
-(LessThanU (FlagLT_ULT)) -> (MOVWconst [1])
-(LessThanU (FlagLT_UGT)) -> (MOVWconst [0])
-(LessThanU (FlagGT_ULT)) -> (MOVWconst [1])
-(LessThanU (FlagGT_UGT)) -> (MOVWconst [0])
-
-(LessEqual (FlagEQ)) -> (MOVWconst [1])
-(LessEqual (FlagLT_ULT)) -> (MOVWconst [1])
-(LessEqual (FlagLT_UGT)) -> (MOVWconst [1])
-(LessEqual (FlagGT_ULT)) -> (MOVWconst [0])
-(LessEqual (FlagGT_UGT)) -> (MOVWconst [0])
-
-(LessEqualU (FlagEQ)) -> (MOVWconst [1])
-(LessEqualU (FlagLT_ULT)) -> (MOVWconst [1])
-(LessEqualU (FlagLT_UGT)) -> (MOVWconst [0])
-(LessEqualU (FlagGT_ULT)) -> (MOVWconst [1])
-(LessEqualU (FlagGT_UGT)) -> (MOVWconst [0])
-
-(GreaterThan (FlagEQ)) -> (MOVWconst [0])
-(GreaterThan (FlagLT_ULT)) -> (MOVWconst [0])
-(GreaterThan (FlagLT_UGT)) -> (MOVWconst [0])
-(GreaterThan (FlagGT_ULT)) -> (MOVWconst [1])
-(GreaterThan (FlagGT_UGT)) -> (MOVWconst [1])
-
-(GreaterThanU (FlagEQ)) -> (MOVWconst [0])
-(GreaterThanU (FlagLT_ULT)) -> (MOVWconst [0])
-(GreaterThanU (FlagLT_UGT)) -> (MOVWconst [1])
-(GreaterThanU (FlagGT_ULT)) -> (MOVWconst [0])
-(GreaterThanU (FlagGT_UGT)) -> (MOVWconst [1])
-
-(GreaterEqual (FlagEQ)) -> (MOVWconst [1])
-(GreaterEqual (FlagLT_ULT)) -> (MOVWconst [0])
-(GreaterEqual (FlagLT_UGT)) -> (MOVWconst [0])
-(GreaterEqual (FlagGT_ULT)) -> (MOVWconst [1])
-(GreaterEqual (FlagGT_UGT)) -> (MOVWconst [1])
-
-(GreaterEqualU (FlagEQ)) -> (MOVWconst [1])
-(GreaterEqualU (FlagLT_ULT)) -> (MOVWconst [0])
-(GreaterEqualU (FlagLT_UGT)) -> (MOVWconst [1])
-(GreaterEqualU (FlagGT_ULT)) -> (MOVWconst [0])
-(GreaterEqualU (FlagGT_UGT)) -> (MOVWconst [1])
+(Equal (FlagConstant [fc])) => (MOVWconst [b2i32(fc.eq())])
+(NotEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ne())])
+(LessThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.lt())])
+(LessThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ult())])
+(LessEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.le())])
+(LessEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ule())])
+(GreaterThan (FlagConstant [fc])) => (MOVWconst [b2i32(fc.gt())])
+(GreaterThanU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ugt())])
+(GreaterEqual (FlagConstant [fc])) => (MOVWconst [b2i32(fc.ge())])
+(GreaterEqualU (FlagConstant [fc])) => (MOVWconst [b2i32(fc.uge())])
// absorb InvertFlags into boolean values
(Equal (InvertFlags x)) -> (Equal x)
@@ -779,26 +704,17 @@
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
// absorb flag constants into conditional instructions
-(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
-(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
-(CMOVWLSconst x (FlagLT_UGT)) -> x
-(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
-(CMOVWLSconst x (FlagGT_UGT)) -> x
-
-(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
-(CMOVWHSconst x (FlagLT_ULT)) -> x
-(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
-(CMOVWHSconst x (FlagGT_ULT)) -> x
-(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
+(CMOVWLSconst _ (FlagConstant [fc]) [c]) && fc.ule() => (MOVWconst [c])
+(CMOVWLSconst x (FlagConstant [fc]) [c]) && fc.ugt() => x
+
+(CMOVWHSconst _ (FlagConstant [fc]) [c]) && fc.uge() => (MOVWconst [c])
+(CMOVWHSconst x (FlagConstant [fc]) [c]) && fc.ult() => x
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
-(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
-(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
-(SRAcond x _ (FlagLT_UGT)) -> (SRAconst x [31])
-(SRAcond x y (FlagGT_ULT)) -> (SRA x y)
-(SRAcond x _ (FlagGT_UGT)) -> (SRAconst x [31])
+(SRAcond x _ (FlagConstant [fc])) && fc.uge() => (SRAconst x [31])
+(SRAcond x y (FlagConstant [fc])) && fc.ult() => (SRA x y)
// remove redundant *const ops
(ADDconst [0] x) -> x
@@ -1417,42 +1333,42 @@
(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no)
(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no)
(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no)
-(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no)
-(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL <x.Type> x y)) yes no)
-(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no)
-(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no)
-(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no)
-(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no)
-(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no)
-(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no)
-(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no)
-(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no)
-(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL <x.Type> x y)) yes no)
-(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no)
-(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no)
-(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no)
-(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no)
-(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no)
-(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no)
-(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no)
-(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no)
-(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL <x.Type> x y)) yes no)
-(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no)
-(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no)
-(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no)
-(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no)
-(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no)
-(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no)
-(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no)
-(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no)
-(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL <x.Type> x y)) yes no)
-(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no)
-(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no)
-(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no)
-(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no)
-(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no)
-(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no)
-(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no)
+(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LTnoov (CMP x y) yes no)
+(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
+(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMPconst [c] x) yes no)
+(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLL x y [c]) yes no)
+(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRL x y [c]) yes no)
+(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRA x y [c]) yes no)
+(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLLreg x y z) yes no)
+(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRLreg x y z) yes no)
+(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRAreg x y z) yes no)
+(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LEnoov (CMP x y) yes no)
+(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
+(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMPconst [c] x) yes no)
+(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLL x y [c]) yes no)
+(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRL x y [c]) yes no)
+(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRA x y [c]) yes no)
+(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLLreg x y z) yes no)
+(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRLreg x y z) yes no)
+(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRAreg x y z) yes no)
+(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LTnoov (CMN x y) yes no)
+(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
+(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMNconst [c] x) yes no)
+(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLL x y [c]) yes no)
+(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRL x y [c]) yes no)
+(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRA x y [c]) yes no)
+(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLLreg x y z) yes no)
+(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRLreg x y z) yes no)
+(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRAreg x y z) yes no)
+(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LEnoov (CMN x y) yes no)
+(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
+(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMNconst [c] x) yes no)
+(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLL x y [c]) yes no)
+(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRL x y [c]) yes no)
+(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRA x y [c]) yes no)
+(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLLreg x y z) yes no)
+(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRLreg x y z) yes no)
+(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRAreg x y z) yes no)
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no)
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no)
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no)
@@ -1485,43 +1401,43 @@
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no)
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no)
-(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no)
-(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL <x.Type> x y)) yes no)
-(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no)
-(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no)
-(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no)
-(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no)
-(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no)
-(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no)
-(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no)
-(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no)
-(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL <x.Type> x y)) yes no)
-(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no)
-(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no)
-(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no)
-(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no)
-(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no)
-(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no)
-(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no)
-(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no)
-(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no)
-(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no)
-(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no)
-(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no)
-(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no)
-(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no)
-(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no)
-(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no)
-(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL <x.Type> x y)) yes no)
-(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no)
-(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no)
-(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no)
-(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no)
-(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no)
-(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no)
-(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no)
+(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GTnoov (CMP x y) yes no)
+(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
+(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMPconst [c] x) yes no)
+(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLL x y [c]) yes no)
+(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRL x y [c]) yes no)
+(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRA x y [c]) yes no)
+(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLLreg x y z) yes no)
+(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRLreg x y z) yes no)
+(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRAreg x y z) yes no)
+(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GEnoov (CMP x y) yes no)
+(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
+(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMPconst [c] x) yes no)
+(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLL x y [c]) yes no)
+(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRL x y [c]) yes no)
+(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRA x y [c]) yes no)
+(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLLreg x y z) yes no)
+(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRLreg x y z) yes no)
+(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRAreg x y z) yes no)
+(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GTnoov (CMN x y) yes no)
+(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMNconst [c] x) yes no)
+(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLL x y [c]) yes no)
+(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRL x y [c]) yes no)
+(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRA x y [c]) yes no)
+(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLLreg x y z) yes no)
+(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRLreg x y z) yes no)
+(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRAreg x y z) yes no)
+(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GEnoov (CMN x y) yes no)
+(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
+(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMNconst [c] x) yes no)
+(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLL x y [c]) yes no)
+(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRL x y [c]) yes no)
+(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRA x y [c]) yes no)
+(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLLreg x y z) yes no)
+(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRLreg x y z) yes no)
+(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRAreg x y z) yes no)
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no)
-(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL <x.Type> x y)) yes no)
+(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no)
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no)
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules
index 03202414d6..442d769fdd 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64.rules
+++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules
@@ -598,31 +598,31 @@
(EQ (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (EQ (CMNconst [c] y) yes no)
(NE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (NE (CMNconst [c] y) yes no)
-(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LT (CMNconst [c] y) yes no)
-(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LE (CMNconst [c] y) yes no)
-(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GT (CMNconst [c] y) yes no)
-(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GE (CMNconst [c] y) yes no)
+(LT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LTnoov (CMNconst [c] y) yes no)
+(LE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LEnoov (CMNconst [c] y) yes no)
+(GT (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GTnoov (CMNconst [c] y) yes no)
+(GE (CMPconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GEnoov (CMNconst [c] y) yes no)
(EQ (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (EQ (CMNWconst [int32(c)] y) yes no)
(NE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (NE (CMNWconst [int32(c)] y) yes no)
-(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LT (CMNWconst [int32(c)] y) yes no)
-(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LE (CMNWconst [int32(c)] y) yes no)
-(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GT (CMNWconst [int32(c)] y) yes no)
-(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GE (CMNWconst [int32(c)] y) yes no)
+(LT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LTnoov (CMNWconst [int32(c)] y) yes no)
+(LE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (LEnoov (CMNWconst [int32(c)] y) yes no)
+(GT (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GTnoov (CMNWconst [int32(c)] y) yes no)
+(GE (CMPWconst [0] x:(ADDconst [c] y)) yes no) && x.Uses == 1 => (GEnoov (CMNWconst [int32(c)] y) yes no)
(EQ (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
(NE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
-(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LT (CMN x y) yes no)
-(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LE (CMN x y) yes no)
-(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GT (CMN x y) yes no)
-(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GE (CMN x y) yes no)
+(LT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LTnoov (CMN x y) yes no)
+(LE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LEnoov (CMN x y) yes no)
+(GT (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMN x y) yes no)
+(GE (CMPconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMN x y) yes no)
(EQ (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (EQ (CMNW x y) yes no)
(NE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (NE (CMNW x y) yes no)
-(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LT (CMNW x y) yes no)
-(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LE (CMNW x y) yes no)
-(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GT (CMNW x y) yes no)
-(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GE (CMNW x y) yes no)
+(LT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LTnoov (CMNW x y) yes no)
+(LE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (LEnoov (CMNW x y) yes no)
+(GT (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GTnoov (CMNW x y) yes no)
+(GE (CMPWconst [0] z:(ADD x y)) yes no) && z.Uses == 1 => (GEnoov (CMNW x y) yes no)
(EQ (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (EQ (CMN x y) yes no)
(NE (CMP x z:(NEG y)) yes no) && z.Uses == 1 => (NE (CMN x y) yes no)
@@ -645,31 +645,31 @@
(EQ (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (EQ (CMN a (MUL <x.Type> x y)) yes no)
(NE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (NE (CMN a (MUL <x.Type> x y)) yes no)
-(LT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LT (CMN a (MUL <x.Type> x y)) yes no)
-(LE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LE (CMN a (MUL <x.Type> x y)) yes no)
-(GT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GT (CMN a (MUL <x.Type> x y)) yes no)
-(GE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GE (CMN a (MUL <x.Type> x y)) yes no)
+(LT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
+(LE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
+(GT (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
+(GE (CMPconst [0] z:(MADD a x y)) yes no) && z.Uses==1 => (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
(EQ (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (EQ (CMP a (MUL <x.Type> x y)) yes no)
(NE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (NE (CMP a (MUL <x.Type> x y)) yes no)
-(LE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LE (CMP a (MUL <x.Type> x y)) yes no)
-(LT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LT (CMP a (MUL <x.Type> x y)) yes no)
-(GE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GE (CMP a (MUL <x.Type> x y)) yes no)
-(GT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GT (CMP a (MUL <x.Type> x y)) yes no)
+(LE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
+(LT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
+(GE (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
+(GT (CMPconst [0] z:(MSUB a x y)) yes no) && z.Uses==1 => (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
(EQ (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (EQ (CMNW a (MULW <x.Type> x y)) yes no)
(NE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (NE (CMNW a (MULW <x.Type> x y)) yes no)
-(LE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LE (CMNW a (MULW <x.Type> x y)) yes no)
-(LT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LT (CMNW a (MULW <x.Type> x y)) yes no)
-(GE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GE (CMNW a (MULW <x.Type> x y)) yes no)
-(GT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GT (CMNW a (MULW <x.Type> x y)) yes no)
+(LE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LEnoov (CMNW a (MULW <x.Type> x y)) yes no)
+(LT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (LTnoov (CMNW a (MULW <x.Type> x y)) yes no)
+(GE (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GEnoov (CMNW a (MULW <x.Type> x y)) yes no)
+(GT (CMPWconst [0] z:(MADDW a x y)) yes no) && z.Uses==1 => (GTnoov (CMNW a (MULW <x.Type> x y)) yes no)
(EQ (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (EQ (CMPW a (MULW <x.Type> x y)) yes no)
(NE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (NE (CMPW a (MULW <x.Type> x y)) yes no)
-(LE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LE (CMPW a (MULW <x.Type> x y)) yes no)
-(LT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LT (CMPW a (MULW <x.Type> x y)) yes no)
-(GE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GE (CMPW a (MULW <x.Type> x y)) yes no)
-(GT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GT (CMPW a (MULW <x.Type> x y)) yes no)
+(LE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LEnoov (CMPW a (MULW <x.Type> x y)) yes no)
+(LT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (LTnoov (CMPW a (MULW <x.Type> x y)) yes no)
+(GE (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GEnoov (CMPW a (MULW <x.Type> x y)) yes no)
+(GT (CMPWconst [0] z:(MSUBW a x y)) yes no) && z.Uses==1 => (GTnoov (CMPW a (MULW <x.Type> x y)) yes no)
// Absorb bit-tests into block
(Z (ANDconst [c] x) yes no) && oneBit(c) => (TBZ [int64(ntz64(c))] x yes no)
@@ -1381,103 +1381,64 @@
(MOVDreg (MOVDconst [c])) -> (MOVDconst [c])
// constant comparisons
-(CMPconst (MOVDconst [x]) [y]) && x==y -> (FlagEQ)
-(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
-(CMPconst (MOVDconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
-(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
-(CMPconst (MOVDconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
-(CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
-(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
-(CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
-(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
-(CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
-(TSTconst (MOVDconst [x]) [y]) && int64(x&y)==0 -> (FlagEQ)
-(TSTconst (MOVDconst [x]) [y]) && int64(x&y)<0 -> (FlagLT_UGT)
-(TSTconst (MOVDconst [x]) [y]) && int64(x&y)>0 -> (FlagGT_UGT)
-(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)==0 -> (FlagEQ)
-(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)<0 -> (FlagLT_UGT)
-(TSTWconst (MOVDconst [x]) [y]) && int32(x&y)>0 -> (FlagGT_UGT)
-(CMNconst (MOVDconst [x]) [y]) && int64(x)==int64(-y) -> (FlagEQ)
-(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)<uint64(-y) -> (FlagLT_ULT)
-(CMNconst (MOVDconst [x]) [y]) && int64(x)<int64(-y) && uint64(x)>uint64(-y) -> (FlagLT_UGT)
-(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)<uint64(-y) -> (FlagGT_ULT)
-(CMNconst (MOVDconst [x]) [y]) && int64(x)>int64(-y) && uint64(x)>uint64(-y) -> (FlagGT_UGT)
-(CMNWconst (MOVDconst [x]) [y]) && int32(x)==int32(-y) -> (FlagEQ)
-(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)<uint32(-y) -> (FlagLT_ULT)
-(CMNWconst (MOVDconst [x]) [y]) && int32(x)<int32(-y) && uint32(x)>uint32(-y) -> (FlagLT_UGT)
-(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)<uint32(-y) -> (FlagGT_ULT)
-(CMNWconst (MOVDconst [x]) [y]) && int32(x)>int32(-y) && uint32(x)>uint32(-y) -> (FlagGT_UGT)
-
+(CMPconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags64(x,y)])
+(CMPWconst (MOVDconst [x]) [y]) => (FlagConstant [subFlags32(int32(x),y)])
+(TSTconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags64(x&y)])
+(TSTWconst (MOVDconst [x]) [y]) => (FlagConstant [logicFlags32(int32(x)&y)])
+(CMNconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags64(x,y)])
+(CMNWconst (MOVDconst [x]) [y]) => (FlagConstant [addFlags32(int32(x),y)])
// other known comparisons
-(CMPconst (MOVBUreg _) [c]) && 0xff < c -> (FlagLT_ULT)
-(CMPconst (MOVHUreg _) [c]) && 0xffff < c -> (FlagLT_ULT)
-(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c -> (FlagLT_ULT)
-(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n -> (FlagLT_ULT)
-(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) -> (FlagLT_ULT)
-(CMPWconst (MOVBUreg _) [c]) && 0xff < int32(c) -> (FlagLT_ULT)
-(CMPWconst (MOVHUreg _) [c]) && 0xffff < int32(c) -> (FlagLT_ULT)
+(CMPconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
+(CMPconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
+(CMPconst (MOVWUreg _) [c]) && 0xffffffff < c => (FlagConstant [subFlags64(0,1)])
+(CMPconst (ANDconst _ [m]) [n]) && 0 <= m && m < n => (FlagConstant [subFlags64(0,1)])
+(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n) => (FlagConstant [subFlags64(0,1)])
+(CMPWconst (MOVBUreg _) [c]) && 0xff < c => (FlagConstant [subFlags64(0,1)])
+(CMPWconst (MOVHUreg _) [c]) && 0xffff < c => (FlagConstant [subFlags64(0,1)])
// absorb flag constants into branches
-(EQ (FlagEQ) yes no) -> (First yes no)
-(EQ (FlagLT_ULT) yes no) -> (First no yes)
-(EQ (FlagLT_UGT) yes no) -> (First no yes)
-(EQ (FlagGT_ULT) yes no) -> (First no yes)
-(EQ (FlagGT_UGT) yes no) -> (First no yes)
-
-(NE (FlagEQ) yes no) -> (First no yes)
-(NE (FlagLT_ULT) yes no) -> (First yes no)
-(NE (FlagLT_UGT) yes no) -> (First yes no)
-(NE (FlagGT_ULT) yes no) -> (First yes no)
-(NE (FlagGT_UGT) yes no) -> (First yes no)
-
-(LT (FlagEQ) yes no) -> (First no yes)
-(LT (FlagLT_ULT) yes no) -> (First yes no)
-(LT (FlagLT_UGT) yes no) -> (First yes no)
-(LT (FlagGT_ULT) yes no) -> (First no yes)
-(LT (FlagGT_UGT) yes no) -> (First no yes)
-
-(LE (FlagEQ) yes no) -> (First yes no)
-(LE (FlagLT_ULT) yes no) -> (First yes no)
-(LE (FlagLT_UGT) yes no) -> (First yes no)
-(LE (FlagGT_ULT) yes no) -> (First no yes)
-(LE (FlagGT_UGT) yes no) -> (First no yes)
-
-(GT (FlagEQ) yes no) -> (First no yes)
-(GT (FlagLT_ULT) yes no) -> (First no yes)
-(GT (FlagLT_UGT) yes no) -> (First no yes)
-(GT (FlagGT_ULT) yes no) -> (First yes no)
-(GT (FlagGT_UGT) yes no) -> (First yes no)
-
-(GE (FlagEQ) yes no) -> (First yes no)
-(GE (FlagLT_ULT) yes no) -> (First no yes)
-(GE (FlagLT_UGT) yes no) -> (First no yes)
-(GE (FlagGT_ULT) yes no) -> (First yes no)
-(GE (FlagGT_UGT) yes no) -> (First yes no)
-
-(ULT (FlagEQ) yes no) -> (First no yes)
-(ULT (FlagLT_ULT) yes no) -> (First yes no)
-(ULT (FlagLT_UGT) yes no) -> (First no yes)
-(ULT (FlagGT_ULT) yes no) -> (First yes no)
-(ULT (FlagGT_UGT) yes no) -> (First no yes)
-
-(ULE (FlagEQ) yes no) -> (First yes no)
-(ULE (FlagLT_ULT) yes no) -> (First yes no)
-(ULE (FlagLT_UGT) yes no) -> (First no yes)
-(ULE (FlagGT_ULT) yes no) -> (First yes no)
-(ULE (FlagGT_UGT) yes no) -> (First no yes)
-
-(UGT (FlagEQ) yes no) -> (First no yes)
-(UGT (FlagLT_ULT) yes no) -> (First no yes)
-(UGT (FlagLT_UGT) yes no) -> (First yes no)
-(UGT (FlagGT_ULT) yes no) -> (First no yes)
-(UGT (FlagGT_UGT) yes no) -> (First yes no)
-
-(UGE (FlagEQ) yes no) -> (First yes no)
-(UGE (FlagLT_ULT) yes no) -> (First no yes)
-(UGE (FlagLT_UGT) yes no) -> (First yes no)
-(UGE (FlagGT_ULT) yes no) -> (First no yes)
-(UGE (FlagGT_UGT) yes no) -> (First yes no)
+(EQ (FlagConstant [fc]) yes no) && fc.eq() => (First yes no)
+(EQ (FlagConstant [fc]) yes no) && !fc.eq() => (First no yes)
+
+(NE (FlagConstant [fc]) yes no) && fc.ne() => (First yes no)
+(NE (FlagConstant [fc]) yes no) && !fc.ne() => (First no yes)
+
+(LT (FlagConstant [fc]) yes no) && fc.lt() => (First yes no)
+(LT (FlagConstant [fc]) yes no) && !fc.lt() => (First no yes)
+
+(LE (FlagConstant [fc]) yes no) && fc.le() => (First yes no)
+(LE (FlagConstant [fc]) yes no) && !fc.le() => (First no yes)
+
+(GT (FlagConstant [fc]) yes no) && fc.gt() => (First yes no)
+(GT (FlagConstant [fc]) yes no) && !fc.gt() => (First no yes)
+
+(GE (FlagConstant [fc]) yes no) && fc.ge() => (First yes no)
+(GE (FlagConstant [fc]) yes no) && !fc.ge() => (First no yes)
+
+(ULT (FlagConstant [fc]) yes no) && fc.ult() => (First yes no)
+(ULT (FlagConstant [fc]) yes no) && !fc.ult() => (First no yes)
+
+(ULE (FlagConstant [fc]) yes no) && fc.ule() => (First yes no)
+(ULE (FlagConstant [fc]) yes no) && !fc.ule() => (First no yes)
+
+(UGT (FlagConstant [fc]) yes no) && fc.ugt() => (First yes no)
+(UGT (FlagConstant [fc]) yes no) && !fc.ugt() => (First no yes)
+
+(UGE (FlagConstant [fc]) yes no) && fc.uge() => (First yes no)
+(UGE (FlagConstant [fc]) yes no) && !fc.uge() => (First no yes)
+
+(LTnoov (FlagConstant [fc]) yes no) && fc.ltNoov() => (First yes no)
+(LTnoov (FlagConstant [fc]) yes no) && !fc.ltNoov() => (First no yes)
+
+(LEnoov (FlagConstant [fc]) yes no) && fc.leNoov() => (First yes no)
+(LEnoov (FlagConstant [fc]) yes no) && !fc.leNoov() => (First no yes)
+
+(GTnoov (FlagConstant [fc]) yes no) && fc.gtNoov() => (First yes no)
+(GTnoov (FlagConstant [fc]) yes no) && !fc.gtNoov() => (First no yes)
+
+(GEnoov (FlagConstant [fc]) yes no) && fc.geNoov() => (First yes no)
+(GEnoov (FlagConstant [fc]) yes no) && !fc.geNoov() => (First no yes)
(Z (MOVDconst [0]) yes no) -> (First yes no)
(Z (MOVDconst [c]) yes no) && c != 0 -> (First no yes)
@@ -1503,71 +1464,26 @@
(FGT (InvertFlags cmp) yes no) -> (FLT cmp yes no)
(FLE (InvertFlags cmp) yes no) -> (FGE cmp yes no)
(FGE (InvertFlags cmp) yes no) -> (FLE cmp yes no)
+(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
+(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
+(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
+(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
// absorb InvertFlags into CSEL(0)
(CSEL {cc} x y (InvertFlags cmp)) -> (CSEL {arm64Invert(cc.(Op))} x y cmp)
(CSEL0 {cc} x (InvertFlags cmp)) -> (CSEL0 {arm64Invert(cc.(Op))} x cmp)
// absorb flag constants into boolean values
-(Equal (FlagEQ)) -> (MOVDconst [1])
-(Equal (FlagLT_ULT)) -> (MOVDconst [0])
-(Equal (FlagLT_UGT)) -> (MOVDconst [0])
-(Equal (FlagGT_ULT)) -> (MOVDconst [0])
-(Equal (FlagGT_UGT)) -> (MOVDconst [0])
-
-(NotEqual (FlagEQ)) -> (MOVDconst [0])
-(NotEqual (FlagLT_ULT)) -> (MOVDconst [1])
-(NotEqual (FlagLT_UGT)) -> (MOVDconst [1])
-(NotEqual (FlagGT_ULT)) -> (MOVDconst [1])
-(NotEqual (FlagGT_UGT)) -> (MOVDconst [1])
-
-(LessThan (FlagEQ)) -> (MOVDconst [0])
-(LessThan (FlagLT_ULT)) -> (MOVDconst [1])
-(LessThan (FlagLT_UGT)) -> (MOVDconst [1])
-(LessThan (FlagGT_ULT)) -> (MOVDconst [0])
-(LessThan (FlagGT_UGT)) -> (MOVDconst [0])
-
-(LessThanU (FlagEQ)) -> (MOVDconst [0])
-(LessThanU (FlagLT_ULT)) -> (MOVDconst [1])
-(LessThanU (FlagLT_UGT)) -> (MOVDconst [0])
-(LessThanU (FlagGT_ULT)) -> (MOVDconst [1])
-(LessThanU (FlagGT_UGT)) -> (MOVDconst [0])
-
-(LessEqual (FlagEQ)) -> (MOVDconst [1])
-(LessEqual (FlagLT_ULT)) -> (MOVDconst [1])
-(LessEqual (FlagLT_UGT)) -> (MOVDconst [1])
-(LessEqual (FlagGT_ULT)) -> (MOVDconst [0])
-(LessEqual (FlagGT_UGT)) -> (MOVDconst [0])
-
-(LessEqualU (FlagEQ)) -> (MOVDconst [1])
-(LessEqualU (FlagLT_ULT)) -> (MOVDconst [1])
-(LessEqualU (FlagLT_UGT)) -> (MOVDconst [0])
-(LessEqualU (FlagGT_ULT)) -> (MOVDconst [1])
-(LessEqualU (FlagGT_UGT)) -> (MOVDconst [0])
-
-(GreaterThan (FlagEQ)) -> (MOVDconst [0])
-(GreaterThan (FlagLT_ULT)) -> (MOVDconst [0])
-(GreaterThan (FlagLT_UGT)) -> (MOVDconst [0])
-(GreaterThan (FlagGT_ULT)) -> (MOVDconst [1])
-(GreaterThan (FlagGT_UGT)) -> (MOVDconst [1])
-
-(GreaterThanU (FlagEQ)) -> (MOVDconst [0])
-(GreaterThanU (FlagLT_ULT)) -> (MOVDconst [0])
-(GreaterThanU (FlagLT_UGT)) -> (MOVDconst [1])
-(GreaterThanU (FlagGT_ULT)) -> (MOVDconst [0])
-(GreaterThanU (FlagGT_UGT)) -> (MOVDconst [1])
-
-(GreaterEqual (FlagEQ)) -> (MOVDconst [1])
-(GreaterEqual (FlagLT_ULT)) -> (MOVDconst [0])
-(GreaterEqual (FlagLT_UGT)) -> (MOVDconst [0])
-(GreaterEqual (FlagGT_ULT)) -> (MOVDconst [1])
-(GreaterEqual (FlagGT_UGT)) -> (MOVDconst [1])
-
-(GreaterEqualU (FlagEQ)) -> (MOVDconst [1])
-(GreaterEqualU (FlagLT_ULT)) -> (MOVDconst [0])
-(GreaterEqualU (FlagLT_UGT)) -> (MOVDconst [1])
-(GreaterEqualU (FlagGT_ULT)) -> (MOVDconst [0])
-(GreaterEqualU (FlagGT_UGT)) -> (MOVDconst [1])
+(Equal (FlagConstant [fc])) => (MOVDconst [b2i(fc.eq())])
+(NotEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ne())])
+(LessThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.lt())])
+(LessThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ult())])
+(LessEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.le())])
+(LessEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ule())])
+(GreaterThan (FlagConstant [fc])) => (MOVDconst [b2i(fc.gt())])
+(GreaterThanU (FlagConstant [fc])) => (MOVDconst [b2i(fc.ugt())])
+(GreaterEqual (FlagConstant [fc])) => (MOVDconst [b2i(fc.ge())])
+(GreaterEqualU (FlagConstant [fc])) => (MOVDconst [b2i(fc.uge())])
// absorb InvertFlags into boolean values
(Equal (InvertFlags x)) -> (Equal x)
diff --git a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
index 73e18bc56a..b402e35ea6 100644
--- a/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/ARM64Ops.go
@@ -587,18 +587,12 @@ func init() {
// See runtime/stubs.go for a more detailed discussion.
{name: "LoweredGetCallerPC", reg: gp01, rematerializeable: true},
- // Constant flag values. For any comparison, there are 5 possible
- // outcomes: the three from the signed total order (<,==,>) and the
- // three from the unsigned total order. The == cases overlap.
- // Note: there's a sixth "unordered" outcome for floating-point
+ // Constant flag value.
+ // Note: there's an "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
- // These ops are for temporary use by rewrite rules. They
+ // This op is for temporary use by rewrite rules. It
// cannot appear in the generated assembly.
- {name: "FlagEQ"}, // equal
- {name: "FlagLT_ULT"}, // signed < and unsigned <
- {name: "FlagLT_UGT"}, // signed < and unsigned >
- {name: "FlagGT_UGT"}, // signed > and unsigned <
- {name: "FlagGT_ULT"}, // signed > and unsigned >
+ {name: "FlagConstant", aux: "FlagConstant"},
// (InvertFlags (CMP a b)) == (CMP b a)
// InvertFlags is a pseudo-op which can't appear in assembly output.
@@ -701,6 +695,10 @@ func init() {
{name: "FLE", controls: 1},
{name: "FGT", controls: 1},
{name: "FGE", controls: 1},
+ {name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
+ {name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
+ {name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
+ {name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
}
archs = append(archs, arch{
diff --git a/src/cmd/compile/internal/ssa/gen/ARMOps.go b/src/cmd/compile/internal/ssa/gen/ARMOps.go
index 4abe5c9a8b..068fecf74c 100644
--- a/src/cmd/compile/internal/ssa/gen/ARMOps.go
+++ b/src/cmd/compile/internal/ssa/gen/ARMOps.go
@@ -550,18 +550,12 @@ func init() {
{name: "LoweredPanicExtendB", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r1, r2}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
{name: "LoweredPanicExtendC", argLength: 4, aux: "Int64", reg: regInfo{inputs: []regMask{r4, r0, r1}}, typ: "Mem", call: true}, // arg0=idxHi, arg1=idxLo, arg2=len, arg3=mem, returns memory. AuxInt contains report code (see PanicExtend in genericOps.go).
- // Constant flag values. For any comparison, there are 5 possible
- // outcomes: the three from the signed total order (<,==,>) and the
- // three from the unsigned total order. The == cases overlap.
- // Note: there's a sixth "unordered" outcome for floating-point
+ // Constant flag value.
+ // Note: there's an "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
- // These ops are for temporary use by rewrite rules. They
+ // This op is for temporary use by rewrite rules. It
// cannot appear in the generated assembly.
- {name: "FlagEQ"}, // equal
- {name: "FlagLT_ULT"}, // signed < and unsigned <
- {name: "FlagLT_UGT"}, // signed < and unsigned >
- {name: "FlagGT_UGT"}, // signed > and unsigned <
- {name: "FlagGT_ULT"}, // signed > and unsigned >
+ {name: "FlagConstant", aux: "FlagConstant"},
// (InvertFlags (CMP a b)) == (CMP b a)
// InvertFlags is a pseudo-op which can't appear in assembly output.
@@ -584,6 +578,10 @@ func init() {
{name: "ULE", controls: 1},
{name: "UGT", controls: 1},
{name: "UGE", controls: 1},
+ {name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
+ {name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
+ {name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
+ {name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
}
archs = append(archs, arch{
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules
index d8041e810f..fd28e10098 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64.rules
+++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules
@@ -153,18 +153,18 @@
(Rsh8x64 x (MOVDconst [c])) && uint64(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
(Rsh8Ux64 x (MOVDconst [c])) && uint64(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
-(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c])
-(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c])
-(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c])
-(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c])
-(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c])
-(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c])
-(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c])
-(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c])
-(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c])
-(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c])
-(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c])
-(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c])
+(Lsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SLDconst x [c&63])
+(Rsh64x32 x (MOVDconst [c])) && uint32(c) < 64 => (SRADconst x [c&63])
+(Rsh64Ux32 x (MOVDconst [c])) && uint32(c) < 64 => (SRDconst x [c&63])
+(Lsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SLWconst x [c&31])
+(Rsh32x32 x (MOVDconst [c])) && uint32(c) < 32 => (SRAWconst x [c&31])
+(Rsh32Ux32 x (MOVDconst [c])) && uint32(c) < 32 => (SRWconst x [c&31])
+(Lsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SLWconst x [c&31])
+(Rsh16x32 x (MOVDconst [c])) && uint32(c) < 16 => (SRAWconst (SignExt16to32 x) [c&15])
+(Rsh16Ux32 x (MOVDconst [c])) && uint32(c) < 16 => (SRWconst (ZeroExt16to32 x) [c&15])
+(Lsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SLWconst x [c&7])
+(Rsh8x32 x (MOVDconst [c])) && uint32(c) < 8 => (SRAWconst (SignExt8to32 x) [c&7])
+(Rsh8Ux32 x (MOVDconst [c])) && uint32(c) < 8 => (SRWconst (ZeroExt8to32 x) [c&7])
// Lower bounded shifts first. No need to check shift value.
(Lsh64x(64|32|16|8) x y) && shiftIsBounded(v) => (SLD x y)
@@ -285,7 +285,8 @@
(MaskIfNotCarry (FlagCarrySet)) => (MOVDconst [0])
(MaskIfNotCarry (FlagCarryClear)) => (MOVDconst [-1])
-(S(RAD|RAW|RD|RW|LD|LW) x (MOVDconst [c])) => (S(RAD|RAW|RD|RW|LD|LW)const [c] x)
+(S(RAD|RD|LD) x (MOVDconst [c])) => (S(RAD|RD|LD)const [c&63 | (c>>6&1*63)] x)
+(S(RAW|RW|LW) x (MOVDconst [c])) => (S(RAW|RW|LW)const [c&31 | (c>>5&1*31)] x)
(Addr {sym} base) => (MOVDaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVDaddr {sym} base)
@@ -785,7 +786,7 @@
(FMOVDstore [off] {sym} ptr (MTVSRD x) mem) => (MOVDstore [off] {sym} ptr x mem)
(MOVDstore [off] {sym} ptr (MFVSRD x) mem) => (FMOVDstore [off] {sym} ptr x mem)
-(MTVSRD (MOVDconst [c])) => (FMOVDconst [math.Float64frombits(uint64(c))])
+(MTVSRD (MOVDconst [c])) && !math.IsNaN(math.Float64frombits(uint64(c))) => (FMOVDconst [math.Float64frombits(uint64(c))])
(MFVSRD (FMOVDconst [c])) => (MOVDconst [int64(math.Float64bits(c))])
(MTVSRD x:(MOVDload [off] {sym} ptr mem)) && x.Uses == 1 && clobber(x) => @x.Block (FMOVDload [off] {sym} ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
index a665734b24..f8bc6cb20b 100644
--- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
+++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go
@@ -194,12 +194,12 @@ func init() {
{name: "FMSUB", argLength: 3, reg: fp31, asm: "FMSUB"}, // arg0*arg1 - arg2
{name: "FMSUBS", argLength: 3, reg: fp31, asm: "FMSUBS"}, // arg0*arg1 - arg2
- {name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // arg0 >>a arg1, 64 bits (all sign if arg1 & 64 != 0)
- {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // arg0 >>a arg1, 32 bits (all sign if arg1 & 32 != 0)
- {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // arg0 >> arg1, 64 bits (0 if arg1 & 64 != 0)
- {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // arg0 >> arg1, 32 bits (0 if arg1 & 32 != 0)
- {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << arg1, 64 bits (0 if arg1 & 64 != 0)
- {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << arg1, 32 bits (0 if arg1 & 32 != 0)
+ {name: "SRAD", argLength: 2, reg: gp21, asm: "SRAD"}, // signed arg0 >> (arg1&127), 64 bit width (note: 127, not 63!)
+ {name: "SRAW", argLength: 2, reg: gp21, asm: "SRAW"}, // signed arg0 >> (arg1&63), 32 bit width
+ {name: "SRD", argLength: 2, reg: gp21, asm: "SRD"}, // unsigned arg0 >> (arg1&127), 64 bit width
+ {name: "SRW", argLength: 2, reg: gp21, asm: "SRW"}, // unsigned arg0 >> (arg1&63), 32 bit width
+ {name: "SLD", argLength: 2, reg: gp21, asm: "SLD"}, // arg0 << (arg1&127), 64 bit width
+ {name: "SLW", argLength: 2, reg: gp21, asm: "SLW"}, // arg0 << (arg1&63), 32 bit width
{name: "ROTL", argLength: 2, reg: gp21, asm: "ROTL"}, // arg0 rotate left by arg1 mod 64
{name: "ROTLW", argLength: 2, reg: gp21, asm: "ROTLW"}, // uint32(arg0) rotate left by arg1 mod 32
@@ -208,12 +208,12 @@ func init() {
{name: "ADDconstForCarry", argLength: 1, reg: regInfo{inputs: []regMask{gp | sp | sb}, clobbers: tmp}, aux: "Int16", asm: "ADDC", typ: "Flags"}, // _, carry := arg0 + auxint
{name: "MaskIfNotCarry", argLength: 1, reg: crgp, asm: "ADDME", typ: "Int64"}, // carry - 1 (if carry then 0 else -1)
- {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // arg0 >>a aux, 64 bits
- {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // arg0 >>a aux, 32 bits
- {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // arg0 >> aux, 64 bits
- {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // arg0 >> aux, 32 bits
- {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << aux, 64 bits
- {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << aux, 32 bits
+ {name: "SRADconst", argLength: 1, reg: gp11, asm: "SRAD", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SRAWconst", argLength: 1, reg: gp11, asm: "SRAW", aux: "Int64"}, // signed arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
+ {name: "SRDconst", argLength: 1, reg: gp11, asm: "SRD", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SRWconst", argLength: 1, reg: gp11, asm: "SRW", aux: "Int64"}, // unsigned arg0 >> auxInt, 0 <= auxInt < 32, 32 bit width
+ {name: "SLDconst", argLength: 1, reg: gp11, asm: "SLD", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 64, 64 bit width
+ {name: "SLWconst", argLength: 1, reg: gp11, asm: "SLW", aux: "Int64"}, // arg0 << auxInt, 0 <= auxInt < 32, 32 bit width
{name: "ROTLconst", argLength: 1, reg: gp11, asm: "ROTL", aux: "Int64"}, // arg0 rotate left by auxInt bits
{name: "ROTLWconst", argLength: 1, reg: gp11, asm: "ROTLW", aux: "Int64"}, // uint32(arg0) rotate left by auxInt bits
diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64.rules b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
index fbd87360ac..9437c8e9d4 100644
--- a/src/cmd/compile/internal/ssa/gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/gen/RISCV64.rules
@@ -445,16 +445,6 @@
(Addr {sym} base) => (MOVaddr {sym} [0] base)
(LocalAddr {sym} base _) => (MOVaddr {sym} base)
-// Conditional branches
-//
-// cond is 1 if true.
-//
-// TODO(prattmic): RISCV branch instructions take two operands to compare,
-// so we could generate more efficient code by computing the condition in the
-// branch itself. This should be revisited now that the compiler has support
-// for two control values (https://golang.org/cl/196557).
-(If cond yes no) => (BNEZ cond yes no)
-
// Calls
(StaticCall ...) => (CALLstatic ...)
(ClosureCall ...) => (CALLclosure ...)
@@ -480,11 +470,31 @@
(AtomicExchange32 ...) => (LoweredAtomicExchange32 ...)
(AtomicExchange64 ...) => (LoweredAtomicExchange64 ...)
+// Conditional branches
+(If cond yes no) => (BNEZ cond yes no)
+
// Optimizations
-// Absorb SNEZ into branch.
+// Absorb SEQZ/SNEZ into branch.
+(BEQZ (SEQZ x) yes no) => (BNEZ x yes no)
+(BEQZ (SNEZ x) yes no) => (BEQZ x yes no)
+(BNEZ (SEQZ x) yes no) => (BEQZ x yes no)
(BNEZ (SNEZ x) yes no) => (BNEZ x yes no)
+// Convert BEQZ/BNEZ into more optimal branch conditions.
+(BEQZ (SUB x y) yes no) => (BEQ x y yes no)
+(BNEZ (SUB x y) yes no) => (BNE x y yes no)
+(BEQZ (SLT x y) yes no) => (BGE x y yes no)
+(BNEZ (SLT x y) yes no) => (BLT x y yes no)
+(BEQZ (SLTU x y) yes no) => (BGEU x y yes no)
+(BNEZ (SLTU x y) yes no) => (BLTU x y yes no)
+
+// Convert branch with zero to BEQZ/BNEZ.
+(BEQ (MOVDconst [0]) cond yes no) => (BEQZ cond yes no)
+(BEQ cond (MOVDconst [0]) yes no) => (BEQZ cond yes no)
+(BNE (MOVDconst [0]) cond yes no) => (BNEZ cond yes no)
+(BNE cond (MOVDconst [0]) yes no) => (BNEZ cond yes no)
+
// Store zero
(MOVBstore [off] {sym} ptr (MOVBconst [0]) mem) => (MOVBstorezero [off] {sym} ptr mem)
(MOVHstore [off] {sym} ptr (MOVHconst [0]) mem) => (MOVHstorezero [off] {sym} ptr mem)
diff --git a/src/cmd/compile/internal/ssa/gen/S390XOps.go b/src/cmd/compile/internal/ssa/gen/S390XOps.go
index c583dada33..710beaddbb 100644
--- a/src/cmd/compile/internal/ssa/gen/S390XOps.go
+++ b/src/cmd/compile/internal/ssa/gen/S390XOps.go
@@ -394,24 +394,25 @@ func init() {
{name: "MOVDconst", reg: gp01, asm: "MOVD", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint
- {name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion)
- {name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion)
- {name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA"}, // convert float64 to int32
- {name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA"}, // convert float64 to int64
- {name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA"}, // convert float32 to int32
- {name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA"}, // convert float32 to int64
- {name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA"}, // convert int32 to float32
- {name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA"}, // convert int32 to float64
- {name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA"}, // convert int64 to float32
- {name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA"}, // convert int64 to float64
- {name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR"}, // convert float32 to uint32
- {name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR"}, // convert float64 to uint32
- {name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR"}, // convert float32 to uint64
- {name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR"}, // convert float64 to uint64
- {name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR"}, // convert uint32 to float32
- {name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR"}, // convert uint32 to float64
- {name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR"}, // convert uint64 to float32
- {name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR"}, // convert uint64 to float64
+ {name: "LDGR", argLength: 1, reg: gpfp, asm: "LDGR"}, // move int64 to float64 (no conversion)
+ {name: "LGDR", argLength: 1, reg: fpgp, asm: "LGDR"}, // move float64 to int64 (no conversion)
+
+ {name: "CFDBRA", argLength: 1, reg: fpgp, asm: "CFDBRA", clobberFlags: true}, // convert float64 to int32
+ {name: "CGDBRA", argLength: 1, reg: fpgp, asm: "CGDBRA", clobberFlags: true}, // convert float64 to int64
+ {name: "CFEBRA", argLength: 1, reg: fpgp, asm: "CFEBRA", clobberFlags: true}, // convert float32 to int32
+ {name: "CGEBRA", argLength: 1, reg: fpgp, asm: "CGEBRA", clobberFlags: true}, // convert float32 to int64
+ {name: "CEFBRA", argLength: 1, reg: gpfp, asm: "CEFBRA", clobberFlags: true}, // convert int32 to float32
+ {name: "CDFBRA", argLength: 1, reg: gpfp, asm: "CDFBRA", clobberFlags: true}, // convert int32 to float64
+ {name: "CEGBRA", argLength: 1, reg: gpfp, asm: "CEGBRA", clobberFlags: true}, // convert int64 to float32
+ {name: "CDGBRA", argLength: 1, reg: gpfp, asm: "CDGBRA", clobberFlags: true}, // convert int64 to float64
+ {name: "CLFEBR", argLength: 1, reg: fpgp, asm: "CLFEBR", clobberFlags: true}, // convert float32 to uint32
+ {name: "CLFDBR", argLength: 1, reg: fpgp, asm: "CLFDBR", clobberFlags: true}, // convert float64 to uint32
+ {name: "CLGEBR", argLength: 1, reg: fpgp, asm: "CLGEBR", clobberFlags: true}, // convert float32 to uint64
+ {name: "CLGDBR", argLength: 1, reg: fpgp, asm: "CLGDBR", clobberFlags: true}, // convert float64 to uint64
+ {name: "CELFBR", argLength: 1, reg: gpfp, asm: "CELFBR", clobberFlags: true}, // convert uint32 to float32
+ {name: "CDLFBR", argLength: 1, reg: gpfp, asm: "CDLFBR", clobberFlags: true}, // convert uint32 to float64
+ {name: "CELGBR", argLength: 1, reg: gpfp, asm: "CELGBR", clobberFlags: true}, // convert uint64 to float32
+ {name: "CDLGBR", argLength: 1, reg: gpfp, asm: "CDLGBR", clobberFlags: true}, // convert uint64 to float64
{name: "LEDBR", argLength: 1, reg: fp11, asm: "LEDBR"}, // convert float64 to float32
{name: "LDEBR", argLength: 1, reg: fp11, asm: "LDEBR"}, // convert float32 to float64
diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
index 0deae280b7..1104e69b4d 100644
--- a/src/cmd/compile/internal/ssa/gen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -1423,7 +1423,7 @@ func parseValue(val string, arch arch, loc string) (op opData, oparch, typ, auxi
func opHasAuxInt(op opData) bool {
switch op.aux {
- case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField":
+ case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "TypSize", "ARM64BitField", "FlagConstant":
return true
}
return false
@@ -1818,6 +1818,8 @@ func (op opData) auxIntType() string {
return "int64"
case "CCop":
return "Op"
+ case "FlagConstant":
+ return "flagConstant"
default:
return "invalid"
}
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index 6f69570b52..6ebdf8c3df 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -77,6 +77,7 @@ const (
auxInt128 // auxInt represents a 128-bit integer. Always 0.
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
+ auxFlagConstant // auxInt is a flagConstant
auxString // aux is a string
auxSym // aux is a symbol (a *gc.Node for locals, an *obj.LSym for globals, or nil for none)
auxSymOff // aux is a symbol, auxInt is an offset
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index d619f36cf5..d27682e3b3 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -61,6 +61,10 @@ const (
BlockARMULE
BlockARMUGT
BlockARMUGE
+ BlockARMLTnoov
+ BlockARMLEnoov
+ BlockARMGTnoov
+ BlockARMGEnoov
BlockARM64EQ
BlockARM64NE
@@ -82,6 +86,10 @@ const (
BlockARM64FLE
BlockARM64FGT
BlockARM64FGE
+ BlockARM64LTnoov
+ BlockARM64LEnoov
+ BlockARM64GTnoov
+ BlockARM64GEnoov
BlockMIPSEQ
BlockMIPSNE
@@ -181,37 +189,45 @@ var blockString = [...]string{
BlockAMD64ORD: "ORD",
BlockAMD64NAN: "NAN",
- BlockARMEQ: "EQ",
- BlockARMNE: "NE",
- BlockARMLT: "LT",
- BlockARMLE: "LE",
- BlockARMGT: "GT",
- BlockARMGE: "GE",
- BlockARMULT: "ULT",
- BlockARMULE: "ULE",
- BlockARMUGT: "UGT",
- BlockARMUGE: "UGE",
+ BlockARMEQ: "EQ",
+ BlockARMNE: "NE",
+ BlockARMLT: "LT",
+ BlockARMLE: "LE",
+ BlockARMGT: "GT",
+ BlockARMGE: "GE",
+ BlockARMULT: "ULT",
+ BlockARMULE: "ULE",
+ BlockARMUGT: "UGT",
+ BlockARMUGE: "UGE",
+ BlockARMLTnoov: "LTnoov",
+ BlockARMLEnoov: "LEnoov",
+ BlockARMGTnoov: "GTnoov",
+ BlockARMGEnoov: "GEnoov",
- BlockARM64EQ: "EQ",
- BlockARM64NE: "NE",
- BlockARM64LT: "LT",
- BlockARM64LE: "LE",
- BlockARM64GT: "GT",
- BlockARM64GE: "GE",
- BlockARM64ULT: "ULT",
- BlockARM64ULE: "ULE",
- BlockARM64UGT: "UGT",
- BlockARM64UGE: "UGE",
- BlockARM64Z: "Z",
- BlockARM64NZ: "NZ",
- BlockARM64ZW: "ZW",
- BlockARM64NZW: "NZW",
- BlockARM64TBZ: "TBZ",
- BlockARM64TBNZ: "TBNZ",
- BlockARM64FLT: "FLT",
- BlockARM64FLE: "FLE",
- BlockARM64FGT: "FGT",
- BlockARM64FGE: "FGE",
+ BlockARM64EQ: "EQ",
+ BlockARM64NE: "NE",
+ BlockARM64LT: "LT",
+ BlockARM64LE: "LE",
+ BlockARM64GT: "GT",
+ BlockARM64GE: "GE",
+ BlockARM64ULT: "ULT",
+ BlockARM64ULE: "ULE",
+ BlockARM64UGT: "UGT",
+ BlockARM64UGE: "UGE",
+ BlockARM64Z: "Z",
+ BlockARM64NZ: "NZ",
+ BlockARM64ZW: "ZW",
+ BlockARM64NZW: "NZW",
+ BlockARM64TBZ: "TBZ",
+ BlockARM64TBNZ: "TBNZ",
+ BlockARM64FLT: "FLT",
+ BlockARM64FLE: "FLE",
+ BlockARM64FGT: "FGT",
+ BlockARM64FGE: "FGE",
+ BlockARM64LTnoov: "LTnoov",
+ BlockARM64LEnoov: "LEnoov",
+ BlockARM64GTnoov: "GTnoov",
+ BlockARM64GEnoov: "GEnoov",
BlockMIPSEQ: "EQ",
BlockMIPSNE: "NE",
@@ -1267,11 +1283,7 @@ const (
OpARMLoweredPanicExtendA
OpARMLoweredPanicExtendB
OpARMLoweredPanicExtendC
- OpARMFlagEQ
- OpARMFlagLT_ULT
- OpARMFlagLT_UGT
- OpARMFlagGT_UGT
- OpARMFlagGT_ULT
+ OpARMFlagConstant
OpARMInvertFlags
OpARMLoweredWB
@@ -1542,11 +1554,7 @@ const (
OpARM64LoweredGetClosurePtr
OpARM64LoweredGetCallerSP
OpARM64LoweredGetCallerPC
- OpARM64FlagEQ
- OpARM64FlagLT_ULT
- OpARM64FlagLT_UGT
- OpARM64FlagGT_UGT
- OpARM64FlagGT_ULT
+ OpARM64FlagConstant
OpARM64InvertFlags
OpARM64LDAR
OpARM64LDARB
@@ -16895,29 +16903,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "FlagEQ",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagLT_ULT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagLT_UGT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagGT_UGT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagGT_ULT",
- argLen: 0,
- reg: regInfo{},
+ name: "FlagConstant",
+ auxType: auxFlagConstant,
+ argLen: 0,
+ reg: regInfo{},
},
{
name: "InvertFlags",
@@ -20505,29 +20494,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "FlagEQ",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagLT_ULT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagLT_UGT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagGT_UGT",
- argLen: 0,
- reg: regInfo{},
- },
- {
- name: "FlagGT_ULT",
- argLen: 0,
- reg: regInfo{},
+ name: "FlagConstant",
+ auxType: auxFlagConstant,
+ argLen: 0,
+ reg: regInfo{},
},
{
name: "InvertFlags",
@@ -30175,9 +30145,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CFDBRA",
- argLen: 1,
- asm: s390x.ACFDBRA,
+ name: "CFDBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACFDBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30188,9 +30159,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CGDBRA",
- argLen: 1,
- asm: s390x.ACGDBRA,
+ name: "CGDBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACGDBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30201,9 +30173,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CFEBRA",
- argLen: 1,
- asm: s390x.ACFEBRA,
+ name: "CFEBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACFEBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30214,9 +30187,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CGEBRA",
- argLen: 1,
- asm: s390x.ACGEBRA,
+ name: "CGEBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACGEBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30227,9 +30201,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CEFBRA",
- argLen: 1,
- asm: s390x.ACEFBRA,
+ name: "CEFBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACEFBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30240,9 +30215,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CDFBRA",
- argLen: 1,
- asm: s390x.ACDFBRA,
+ name: "CDFBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACDFBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30253,9 +30229,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CEGBRA",
- argLen: 1,
- asm: s390x.ACEGBRA,
+ name: "CEGBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACEGBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30266,9 +30243,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CDGBRA",
- argLen: 1,
- asm: s390x.ACDGBRA,
+ name: "CDGBRA",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACDGBRA,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30279,9 +30257,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CLFEBR",
- argLen: 1,
- asm: s390x.ACLFEBR,
+ name: "CLFEBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACLFEBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30292,9 +30271,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CLFDBR",
- argLen: 1,
- asm: s390x.ACLFDBR,
+ name: "CLFDBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACLFDBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30305,9 +30285,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CLGEBR",
- argLen: 1,
- asm: s390x.ACLGEBR,
+ name: "CLGEBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACLGEBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30318,9 +30299,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CLGDBR",
- argLen: 1,
- asm: s390x.ACLGDBR,
+ name: "CLGDBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACLGDBR,
reg: regInfo{
inputs: []inputInfo{
{0, 4294901760}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15
@@ -30331,9 +30313,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CELFBR",
- argLen: 1,
- asm: s390x.ACELFBR,
+ name: "CELFBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACELFBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30344,9 +30327,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CDLFBR",
- argLen: 1,
- asm: s390x.ACDLFBR,
+ name: "CDLFBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACDLFBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30357,9 +30341,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CELGBR",
- argLen: 1,
- asm: s390x.ACELGBR,
+ name: "CELGBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACELGBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
@@ -30370,9 +30355,10 @@ var opcodeTable = [...]opInfo{
},
},
{
- name: "CDLGBR",
- argLen: 1,
- asm: s390x.ACDLGBR,
+ name: "CDLGBR",
+ argLen: 1,
+ clobberFlags: true,
+ asm: s390x.ACDLGBR,
reg: regInfo{
inputs: []inputInfo{
{0, 23551}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R11 R12 R14
diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go
index 12c2580c95..a8e43d0114 100644
--- a/src/cmd/compile/internal/ssa/prove.go
+++ b/src/cmd/compile/internal/ssa/prove.go
@@ -1189,15 +1189,38 @@ func simplifyBlock(sdom SparseTree, ft *factsTable, b *Block) {
}
v.Op = ctzNonZeroOp[v.Op]
}
-
+ case OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
+ OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
+ OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
+ OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64:
+ // Check whether, for a >> b, we know that a is non-negative
+ // and b is all of a's bits except the MSB. If so, a is shifted to zero.
+ bits := 8 * v.Type.Size()
+ if v.Args[1].isGenericIntConst() && v.Args[1].AuxInt >= bits-1 && ft.isNonNegative(v.Args[0]) {
+ if b.Func.pass.debug > 0 {
+ b.Func.Warnl(v.Pos, "Proved %v shifts to zero", v.Op)
+ }
+ switch bits {
+ case 64:
+ v.reset(OpConst64)
+ case 32:
+ v.reset(OpConst32)
+ case 16:
+ v.reset(OpConst16)
+ case 8:
+ v.reset(OpConst8)
+ default:
+ panic("unexpected integer size")
+ }
+ v.AuxInt = 0
+ continue // Be sure not to fallthrough - this is no longer OpRsh.
+ }
+ // If the Rsh hasn't been replaced with 0, still check if it is bounded.
+ fallthrough
case OpLsh8x8, OpLsh8x16, OpLsh8x32, OpLsh8x64,
OpLsh16x8, OpLsh16x16, OpLsh16x32, OpLsh16x64,
OpLsh32x8, OpLsh32x16, OpLsh32x32, OpLsh32x64,
OpLsh64x8, OpLsh64x16, OpLsh64x32, OpLsh64x64,
- OpRsh8x8, OpRsh8x16, OpRsh8x32, OpRsh8x64,
- OpRsh16x8, OpRsh16x16, OpRsh16x32, OpRsh16x64,
- OpRsh32x8, OpRsh32x16, OpRsh32x32, OpRsh32x64,
- OpRsh64x8, OpRsh64x16, OpRsh64x32, OpRsh64x64,
OpRsh8Ux8, OpRsh8Ux16, OpRsh8Ux32, OpRsh8Ux64,
OpRsh16Ux8, OpRsh16Ux16, OpRsh16Ux32, OpRsh16Ux64,
OpRsh32Ux8, OpRsh32Ux16, OpRsh32Ux32, OpRsh32Ux64,
diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go
index d97497e24f..2152b1675a 100644
--- a/src/cmd/compile/internal/ssa/rewrite.go
+++ b/src/cmd/compile/internal/ssa/rewrite.go
@@ -511,6 +511,14 @@ func b2i(b bool) int64 {
return 0
}
+// b2i32 translates a boolean value to 0 or 1.
+func b2i32(b bool) int32 {
+ if b {
+ return 1
+ }
+ return 0
+}
+
// shiftIsBounded reports whether (left/right) shift Value v is known to be bounded.
// A shift is bounded if it is shifting by less than the width of the shifted value.
func shiftIsBounded(v *Value) bool {
@@ -616,6 +624,9 @@ func auxIntToInt128(x int64) int128 {
}
return 0
}
+func auxIntToFlagConstant(x int64) flagConstant {
+ return flagConstant(x)
+}
func boolToAuxInt(b bool) int64 {
if b {
@@ -653,6 +664,9 @@ func int128ToAuxInt(x int128) int64 {
}
return 0
}
+func flagConstantToAuxInt(x flagConstant) int64 {
+ return int64(x)
+}
func auxToString(i interface{}) string {
return i.(string)
@@ -997,52 +1011,42 @@ func arm64Invert(op Op) Op {
func ccARM64Eval(cc interface{}, flags *Value) int {
op := cc.(Op)
fop := flags.Op
- switch fop {
- case OpARM64InvertFlags:
+ if fop == OpARM64InvertFlags {
return -ccARM64Eval(op, flags.Args[0])
- case OpARM64FlagEQ:
- switch op {
- case OpARM64Equal, OpARM64GreaterEqual, OpARM64LessEqual,
- OpARM64GreaterEqualU, OpARM64LessEqualU:
- return 1
- default:
- return -1
- }
- case OpARM64FlagLT_ULT:
- switch op {
- case OpARM64LessThan, OpARM64LessThanU,
- OpARM64LessEqual, OpARM64LessEqualU:
- return 1
- default:
- return -1
- }
- case OpARM64FlagLT_UGT:
- switch op {
- case OpARM64LessThan, OpARM64GreaterThanU,
- OpARM64LessEqual, OpARM64GreaterEqualU:
- return 1
- default:
- return -1
- }
- case OpARM64FlagGT_ULT:
- switch op {
- case OpARM64GreaterThan, OpARM64LessThanU,
- OpARM64GreaterEqual, OpARM64LessEqualU:
- return 1
- default:
- return -1
- }
- case OpARM64FlagGT_UGT:
- switch op {
- case OpARM64GreaterThan, OpARM64GreaterThanU,
- OpARM64GreaterEqual, OpARM64GreaterEqualU:
+ }
+ if fop != OpARM64FlagConstant {
+ return 0
+ }
+ fc := flagConstant(flags.AuxInt)
+ b2i := func(b bool) int {
+ if b {
return 1
- default:
- return -1
}
- default:
- return 0
+ return -1
}
+ switch op {
+ case OpARM64Equal:
+ return b2i(fc.eq())
+ case OpARM64NotEqual:
+ return b2i(fc.ne())
+ case OpARM64LessThan:
+ return b2i(fc.lt())
+ case OpARM64LessThanU:
+ return b2i(fc.ult())
+ case OpARM64GreaterThan:
+ return b2i(fc.gt())
+ case OpARM64GreaterThanU:
+ return b2i(fc.ugt())
+ case OpARM64LessEqual:
+ return b2i(fc.le())
+ case OpARM64LessEqualU:
+ return b2i(fc.ule())
+ case OpARM64GreaterEqual:
+ return b2i(fc.ge())
+ case OpARM64GreaterEqualU:
+ return b2i(fc.uge())
+ }
+ return 0
}
// logRule logs the use of the rule s. This will only be enabled if
@@ -1473,3 +1477,170 @@ func sequentialAddresses(x, y *Value, n int64) bool {
}
return false
}
+
+// flagConstant represents the result of a compile-time comparison.
+// The sense of these flags does not necessarily represent the hardware's notion
+// of a flags register - these are just a compile-time construct.
+// We happen to match the semantics to those of arm/arm64.
+// Note that these semantics differ from x86: the carry flag has the opposite
+// sense on a subtraction!
+// On amd64, C=1 represents a borrow, e.g. SBB on amd64 does x - y - C.
+// On arm64, C=0 represents a borrow, e.g. SBC on arm64 does x - y - ^C.
+// (because it does x + ^y + C).
+// See https://en.wikipedia.org/wiki/Carry_flag#Vs._borrow_flag
+type flagConstant uint8
+
+// N reports whether the result of an operation is negative (high bit set).
+func (fc flagConstant) N() bool {
+ return fc&1 != 0
+}
+
+// Z reports whether the result of an operation is 0.
+func (fc flagConstant) Z() bool {
+ return fc&2 != 0
+}
+
+// C reports whether an unsigned add overflowed (carry), or an
+// unsigned subtract did not underflow (borrow).
+func (fc flagConstant) C() bool {
+ return fc&4 != 0
+}
+
+// V reports whether a signed operation overflowed or underflowed.
+func (fc flagConstant) V() bool {
+ return fc&8 != 0
+}
+
+func (fc flagConstant) eq() bool {
+ return fc.Z()
+}
+func (fc flagConstant) ne() bool {
+ return !fc.Z()
+}
+func (fc flagConstant) lt() bool {
+ return fc.N() != fc.V()
+}
+func (fc flagConstant) le() bool {
+ return fc.Z() || fc.lt()
+}
+func (fc flagConstant) gt() bool {
+ return !fc.Z() && fc.ge()
+}
+func (fc flagConstant) ge() bool {
+ return fc.N() == fc.V()
+}
+func (fc flagConstant) ult() bool {
+ return !fc.C()
+}
+func (fc flagConstant) ule() bool {
+ return fc.Z() || fc.ult()
+}
+func (fc flagConstant) ugt() bool {
+ return !fc.Z() && fc.uge()
+}
+func (fc flagConstant) uge() bool {
+ return fc.C()
+}
+
+func (fc flagConstant) ltNoov() bool {
+ return fc.lt() && !fc.V()
+}
+func (fc flagConstant) leNoov() bool {
+ return fc.le() && !fc.V()
+}
+func (fc flagConstant) gtNoov() bool {
+ return fc.gt() && !fc.V()
+}
+func (fc flagConstant) geNoov() bool {
+ return fc.ge() && !fc.V()
+}
+
+func (fc flagConstant) String() string {
+ return fmt.Sprintf("N=%v,Z=%v,C=%v,V=%v", fc.N(), fc.Z(), fc.C(), fc.V())
+}
+
+type flagConstantBuilder struct {
+ N bool
+ Z bool
+ C bool
+ V bool
+}
+
+func (fcs flagConstantBuilder) encode() flagConstant {
+ var fc flagConstant
+ if fcs.N {
+ fc |= 1
+ }
+ if fcs.Z {
+ fc |= 2
+ }
+ if fcs.C {
+ fc |= 4
+ }
+ if fcs.V {
+ fc |= 8
+ }
+ return fc
+}
+
+// Note: addFlags(x,y) != subFlags(x,-y) in some situations:
+// - the results of the C flag are different
+// - the results of the V flag when y==minint are different
+
+// addFlags64 returns the flags that would be set from computing x+y.
+func addFlags64(x, y int64) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x+y == 0
+ fcb.N = x+y < 0
+ fcb.C = uint64(x+y) < uint64(x)
+ fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
+ return fcb.encode()
+}
+
+// subFlags64 returns the flags that would be set from computing x-y.
+func subFlags64(x, y int64) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x-y == 0
+ fcb.N = x-y < 0
+ fcb.C = uint64(y) <= uint64(x) // This code follows the arm carry flag model.
+ fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
+ return fcb.encode()
+}
+
+// addFlags32 returns the flags that would be set from computing x+y.
+func addFlags32(x, y int32) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x+y == 0
+ fcb.N = x+y < 0
+ fcb.C = uint32(x+y) < uint32(x)
+ fcb.V = x >= 0 && y >= 0 && x+y < 0 || x < 0 && y < 0 && x+y >= 0
+ return fcb.encode()
+}
+
+// subFlags32 returns the flags that would be set from computing x-y.
+func subFlags32(x, y int32) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x-y == 0
+ fcb.N = x-y < 0
+ fcb.C = uint32(y) <= uint32(x) // This code follows the arm carry flag model.
+ fcb.V = x >= 0 && y < 0 && x-y < 0 || x < 0 && y >= 0 && x-y >= 0
+ return fcb.encode()
+}
+
+// logicFlags64 returns flags set to the sign/zeroness of x.
+// C and V are set to false.
+func logicFlags64(x int64) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x == 0
+ fcb.N = x < 0
+ return fcb.encode()
+}
+
+// logicFlags32 returns flags set to the sign/zeroness of x.
+// C and V are set to false.
+func logicFlags32(x int32) flagConstant {
+ var fcb flagConstantBuilder
+ fcb.Z = x == 0
+ fcb.N = x < 0
+ return fcb.encode()
+}
diff --git a/src/cmd/compile/internal/ssa/rewriteARM.go b/src/cmd/compile/internal/ssa/rewriteARM.go
index 5c8dd0f2ed..f55e542505 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM.go
@@ -3382,78 +3382,15 @@ func rewriteValueARM_OpARMCMN(v *Value) bool {
func rewriteValueARM_OpARMCMNconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMNconst (MOVWconst [x]) [y])
- // cond: int32(x)==int32(-y)
- // result: (FlagEQ)
+ // result: (FlagConstant [addFlags32(x,y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- x := v_0.AuxInt
- if !(int32(x) == int32(-y)) {
- break
- }
- v.reset(OpARMFlagEQ)
- return true
- }
- // match: (CMNconst (MOVWconst [x]) [y])
- // cond: int32(x)<int32(-y) && uint32(x)<uint32(-y)
- // result: (FlagLT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(-y) && uint32(x) < uint32(-y)) {
- break
- }
- v.reset(OpARMFlagLT_ULT)
- return true
- }
- // match: (CMNconst (MOVWconst [x]) [y])
- // cond: int32(x)<int32(-y) && uint32(x)>uint32(-y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(-y) && uint32(x) > uint32(-y)) {
- break
- }
- v.reset(OpARMFlagLT_UGT)
- return true
- }
- // match: (CMNconst (MOVWconst [x]) [y])
- // cond: int32(x)>int32(-y) && uint32(x)<uint32(-y)
- // result: (FlagGT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(-y) && uint32(x) < uint32(-y)) {
- break
- }
- v.reset(OpARMFlagGT_ULT)
- return true
- }
- // match: (CMNconst (MOVWconst [x]) [y])
- // cond: int32(x)>int32(-y) && uint32(x)>uint32(-y)
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(-y) && uint32(x) > uint32(-y)) {
- break
- }
- v.reset(OpARMFlagGT_UGT)
+ x := auxIntToInt32(v_0.AuxInt)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(addFlags32(x, y))
return true
}
return false
@@ -3683,57 +3620,35 @@ func rewriteValueARM_OpARMCMNshiftRLreg(v *Value) bool {
func rewriteValueARM_OpARMCMOVWHSconst(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- // match: (CMOVWHSconst _ (FlagEQ) [c])
+ // match: (CMOVWHSconst _ (FlagConstant [fc]) [c])
+ // cond: fc.uge()
// result: (MOVWconst [c])
for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagEQ {
+ c := auxIntToInt32(v.AuxInt)
+ if v_1.Op != OpARMFlagConstant {
break
}
- v.reset(OpARMMOVWconst)
- v.AuxInt = c
- return true
- }
- // match: (CMOVWHSconst x (FlagLT_ULT))
- // result: x
- for {
- x := v_0
- if v_1.Op != OpARMFlagLT_ULT {
- break
- }
- v.copyOf(x)
- return true
- }
- // match: (CMOVWHSconst _ (FlagLT_UGT) [c])
- // result: (MOVWconst [c])
- for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagLT_UGT {
+ fc := auxIntToFlagConstant(v_1.AuxInt)
+ if !(fc.uge()) {
break
}
v.reset(OpARMMOVWconst)
- v.AuxInt = c
+ v.AuxInt = int32ToAuxInt(c)
return true
}
- // match: (CMOVWHSconst x (FlagGT_ULT))
+ // match: (CMOVWHSconst x (FlagConstant [fc]) [c])
+ // cond: fc.ult()
// result: x
for {
x := v_0
- if v_1.Op != OpARMFlagGT_ULT {
+ if v_1.Op != OpARMFlagConstant {
break
}
- v.copyOf(x)
- return true
- }
- // match: (CMOVWHSconst _ (FlagGT_UGT) [c])
- // result: (MOVWconst [c])
- for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagGT_UGT {
+ fc := auxIntToFlagConstant(v_1.AuxInt)
+ if !(fc.ult()) {
break
}
- v.reset(OpARMMOVWconst)
- v.AuxInt = c
+ v.copyOf(x)
return true
}
// match: (CMOVWHSconst x (InvertFlags flags) [c])
@@ -3755,54 +3670,32 @@ func rewriteValueARM_OpARMCMOVWHSconst(v *Value) bool {
func rewriteValueARM_OpARMCMOVWLSconst(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
- // match: (CMOVWLSconst _ (FlagEQ) [c])
+ // match: (CMOVWLSconst _ (FlagConstant [fc]) [c])
+ // cond: fc.ule()
// result: (MOVWconst [c])
for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagEQ {
+ c := auxIntToInt32(v.AuxInt)
+ if v_1.Op != OpARMFlagConstant {
break
}
- v.reset(OpARMMOVWconst)
- v.AuxInt = c
- return true
- }
- // match: (CMOVWLSconst _ (FlagLT_ULT) [c])
- // result: (MOVWconst [c])
- for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagLT_ULT {
+ fc := auxIntToFlagConstant(v_1.AuxInt)
+ if !(fc.ule()) {
break
}
v.reset(OpARMMOVWconst)
- v.AuxInt = c
+ v.AuxInt = int32ToAuxInt(c)
return true
}
- // match: (CMOVWLSconst x (FlagLT_UGT))
+ // match: (CMOVWLSconst x (FlagConstant [fc]) [c])
+ // cond: fc.ugt()
// result: x
for {
x := v_0
- if v_1.Op != OpARMFlagLT_UGT {
- break
- }
- v.copyOf(x)
- return true
- }
- // match: (CMOVWLSconst _ (FlagGT_ULT) [c])
- // result: (MOVWconst [c])
- for {
- c := v.AuxInt
- if v_1.Op != OpARMFlagGT_ULT {
+ if v_1.Op != OpARMFlagConstant {
break
}
- v.reset(OpARMMOVWconst)
- v.AuxInt = c
- return true
- }
- // match: (CMOVWLSconst x (FlagGT_UGT))
- // result: x
- for {
- x := v_0
- if v_1.Op != OpARMFlagGT_UGT {
+ fc := auxIntToFlagConstant(v_1.AuxInt)
+ if !(fc.ugt()) {
break
}
v.copyOf(x)
@@ -4094,130 +3987,71 @@ func rewriteValueARM_OpARMCMPF(v *Value) bool {
func rewriteValueARM_OpARMCMPconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMPconst (MOVWconst [x]) [y])
- // cond: int32(x)==int32(y)
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) == int32(y)) {
- break
- }
- v.reset(OpARMFlagEQ)
- return true
- }
- // match: (CMPconst (MOVWconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
- // result: (FlagLT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
- break
- }
- v.reset(OpARMFlagLT_ULT)
- return true
- }
- // match: (CMPconst (MOVWconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
- break
- }
- v.reset(OpARMFlagLT_UGT)
- return true
- }
- // match: (CMPconst (MOVWconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
- // result: (FlagGT_ULT)
+ // result: (FlagConstant [subFlags32(x,y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- x := v_0.AuxInt
- if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
- break
- }
- v.reset(OpARMFlagGT_ULT)
- return true
- }
- // match: (CMPconst (MOVWconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
- break
- }
- v.reset(OpARMFlagGT_UGT)
+ x := auxIntToInt32(v_0.AuxInt)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(x, y))
return true
}
// match: (CMPconst (MOVBUreg _) [c])
// cond: 0xff < c
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags32(0, 1)])
for {
- c := v.AuxInt
+ c := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVBUreg || !(0xff < c) {
break
}
- v.reset(OpARMFlagLT_ULT)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(0, 1))
return true
}
// match: (CMPconst (MOVHUreg _) [c])
// cond: 0xffff < c
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags32(0, 1)])
for {
- c := v.AuxInt
+ c := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVHUreg || !(0xffff < c) {
break
}
- v.reset(OpARMFlagLT_ULT)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(0, 1))
return true
}
// match: (CMPconst (ANDconst _ [m]) [n])
- // cond: 0 <= int32(m) && int32(m) < int32(n)
- // result: (FlagLT_ULT)
+ // cond: 0 <= m && m < n
+ // result: (FlagConstant [subFlags32(0, 1)])
for {
- n := v.AuxInt
+ n := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMANDconst {
break
}
- m := v_0.AuxInt
- if !(0 <= int32(m) && int32(m) < int32(n)) {
+ m := auxIntToInt32(v_0.AuxInt)
+ if !(0 <= m && m < n) {
break
}
- v.reset(OpARMFlagLT_ULT)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(0, 1))
return true
}
// match: (CMPconst (SRLconst _ [c]) [n])
// cond: 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n)
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags32(0, 1)])
for {
- n := v.AuxInt
+ n := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMSRLconst {
break
}
- c := v_0.AuxInt
+ c := auxIntToInt32(v_0.AuxInt)
if !(0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n)) {
break
}
- v.reset(OpARMFlagLT_ULT)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(0, 1))
return true
}
return false
@@ -4458,54 +4292,15 @@ func rewriteValueARM_OpARMCMPshiftRLreg(v *Value) bool {
}
func rewriteValueARM_OpARMEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (Equal (FlagEQ))
- // result: (MOVWconst [1])
+ // match: (Equal (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.eq())])
for {
- if v_0.Op != OpARMFlagEQ {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (Equal (FlagLT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagLT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagGT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagGT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
+ v.AuxInt = int32ToAuxInt(b2i32(fc.eq()))
return true
}
// match: (Equal (InvertFlags x))
@@ -4523,54 +4318,15 @@ func rewriteValueARM_OpARMEqual(v *Value) bool {
}
func rewriteValueARM_OpARMGreaterEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterEqual (FlagEQ))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqual (FlagLT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqual (FlagLT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqual (FlagGT_ULT))
- // result: (MOVWconst [1])
+ // match: (GreaterEqual (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.ge())])
for {
- if v_0.Op != OpARMFlagGT_ULT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqual (FlagGT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
+ v.AuxInt = int32ToAuxInt(b2i32(fc.ge()))
return true
}
// match: (GreaterEqual (InvertFlags x))
@@ -4588,54 +4344,15 @@ func rewriteValueARM_OpARMGreaterEqual(v *Value) bool {
}
func rewriteValueARM_OpARMGreaterEqualU(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterEqualU (FlagEQ))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqualU (FlagLT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqualU (FlagLT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqualU (FlagGT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqualU (FlagGT_UGT))
- // result: (MOVWconst [1])
+ // match: (GreaterEqualU (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.uge())])
for {
- if v_0.Op != OpARMFlagGT_UGT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
+ v.AuxInt = int32ToAuxInt(b2i32(fc.uge()))
return true
}
// match: (GreaterEqualU (InvertFlags x))
@@ -4653,54 +4370,15 @@ func rewriteValueARM_OpARMGreaterEqualU(v *Value) bool {
}
func rewriteValueARM_OpARMGreaterThan(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterThan (FlagEQ))
- // result: (MOVWconst [0])
+ // match: (GreaterThan (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.gt())])
for {
- if v_0.Op != OpARMFlagEQ {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagLT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagLT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagGT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterThan (FlagGT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
+ v.AuxInt = int32ToAuxInt(b2i32(fc.gt()))
return true
}
// match: (GreaterThan (InvertFlags x))
@@ -4718,54 +4396,15 @@ func rewriteValueARM_OpARMGreaterThan(v *Value) bool {
}
func rewriteValueARM_OpARMGreaterThanU(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterThanU (FlagEQ))
- // result: (MOVWconst [0])
+ // match: (GreaterThanU (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.ugt())])
for {
- if v_0.Op != OpARMFlagEQ {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagLT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagLT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterThanU (FlagGT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagGT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
+ v.AuxInt = int32ToAuxInt(b2i32(fc.ugt()))
return true
}
// match: (GreaterThanU (InvertFlags x))
@@ -4783,54 +4422,15 @@ func rewriteValueARM_OpARMGreaterThanU(v *Value) bool {
}
func rewriteValueARM_OpARMLessEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessEqual (FlagEQ))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagLT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagLT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagGT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessEqual (FlagGT_UGT))
- // result: (MOVWconst [0])
+ // match: (LessEqual (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.le())])
for {
- if v_0.Op != OpARMFlagGT_UGT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 0
+ v.AuxInt = int32ToAuxInt(b2i32(fc.le()))
return true
}
// match: (LessEqual (InvertFlags x))
@@ -4848,54 +4448,15 @@ func rewriteValueARM_OpARMLessEqual(v *Value) bool {
}
func rewriteValueARM_OpARMLessEqualU(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessEqualU (FlagEQ))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagLT_ULT))
- // result: (MOVWconst [1])
+ // match: (LessEqualU (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.ule())])
for {
- if v_0.Op != OpARMFlagLT_ULT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagLT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessEqualU (FlagGT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagGT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
+ v.AuxInt = int32ToAuxInt(b2i32(fc.ule()))
return true
}
// match: (LessEqualU (InvertFlags x))
@@ -4913,54 +4474,15 @@ func rewriteValueARM_OpARMLessEqualU(v *Value) bool {
}
func rewriteValueARM_OpARMLessThan(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessThan (FlagEQ))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThan (FlagLT_ULT))
- // result: (MOVWconst [1])
+ // match: (LessThan (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.lt())])
for {
- if v_0.Op != OpARMFlagLT_ULT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThan (FlagLT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThan (FlagGT_ULT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThan (FlagGT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
+ v.AuxInt = int32ToAuxInt(b2i32(fc.lt()))
return true
}
// match: (LessThan (InvertFlags x))
@@ -4978,54 +4500,15 @@ func rewriteValueARM_OpARMLessThan(v *Value) bool {
}
func rewriteValueARM_OpARMLessThanU(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessThanU (FlagEQ))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThanU (FlagLT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThanU (FlagLT_UGT))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagLT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThanU (FlagGT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThanU (FlagGT_UGT))
- // result: (MOVWconst [0])
+ // match: (LessThanU (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.ult())])
for {
- if v_0.Op != OpARMFlagGT_UGT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 0
+ v.AuxInt = int32ToAuxInt(b2i32(fc.ult()))
return true
}
// match: (LessThanU (InvertFlags x))
@@ -8796,54 +8279,15 @@ func rewriteValueARM_OpARMNMULF(v *Value) bool {
}
func rewriteValueARM_OpARMNotEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (NotEqual (FlagEQ))
- // result: (MOVWconst [0])
- for {
- if v_0.Op != OpARMFlagEQ {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 0
- return true
- }
- // match: (NotEqual (FlagLT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagLT_UGT))
- // result: (MOVWconst [1])
+ // match: (NotEqual (FlagConstant [fc]))
+ // result: (MOVWconst [b2i32(fc.ne())])
for {
- if v_0.Op != OpARMFlagLT_UGT {
+ if v_0.Op != OpARMFlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagGT_ULT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_ULT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagGT_UGT))
- // result: (MOVWconst [1])
- for {
- if v_0.Op != OpARMFlagGT_UGT {
- break
- }
- v.reset(OpARMMOVWconst)
- v.AuxInt = 1
+ v.AuxInt = int32ToAuxInt(b2i32(fc.ne()))
return true
}
// match: (NotEqual (InvertFlags x))
@@ -10968,64 +10412,38 @@ func rewriteValueARM_OpARMSRAcond(v *Value) bool {
v_2 := v.Args[2]
v_1 := v.Args[1]
v_0 := v.Args[0]
- // match: (SRAcond x _ (FlagEQ))
+ // match: (SRAcond x _ (FlagConstant [fc]))
+ // cond: fc.uge()
// result: (SRAconst x [31])
for {
x := v_0
- if v_2.Op != OpARMFlagEQ {
+ if v_2.Op != OpARMFlagConstant {
break
}
- v.reset(OpARMSRAconst)
- v.AuxInt = 31
- v.AddArg(x)
- return true
- }
- // match: (SRAcond x y (FlagLT_ULT))
- // result: (SRA x y)
- for {
- x := v_0
- y := v_1
- if v_2.Op != OpARMFlagLT_ULT {
- break
- }
- v.reset(OpARMSRA)
- v.AddArg2(x, y)
- return true
- }
- // match: (SRAcond x _ (FlagLT_UGT))
- // result: (SRAconst x [31])
- for {
- x := v_0
- if v_2.Op != OpARMFlagLT_UGT {
+ fc := auxIntToFlagConstant(v_2.AuxInt)
+ if !(fc.uge()) {
break
}
v.reset(OpARMSRAconst)
- v.AuxInt = 31
+ v.AuxInt = int32ToAuxInt(31)
v.AddArg(x)
return true
}
- // match: (SRAcond x y (FlagGT_ULT))
+ // match: (SRAcond x y (FlagConstant [fc]))
+ // cond: fc.ult()
// result: (SRA x y)
for {
x := v_0
y := v_1
- if v_2.Op != OpARMFlagGT_ULT {
+ if v_2.Op != OpARMFlagConstant {
break
}
- v.reset(OpARMSRA)
- v.AddArg2(x, y)
- return true
- }
- // match: (SRAcond x _ (FlagGT_UGT))
- // result: (SRAconst x [31])
- for {
- x := v_0
- if v_2.Op != OpARMFlagGT_UGT {
+ fc := auxIntToFlagConstant(v_2.AuxInt)
+ if !(fc.ult()) {
break
}
- v.reset(OpARMSRAconst)
- v.AuxInt = 31
- v.AddArg(x)
+ v.reset(OpARMSRA)
+ v.AddArg2(x, y)
return true
}
return false
@@ -12325,48 +11743,15 @@ func rewriteValueARM_OpARMTEQ(v *Value) bool {
func rewriteValueARM_OpARMTEQconst(v *Value) bool {
v_0 := v.Args[0]
// match: (TEQconst (MOVWconst [x]) [y])
- // cond: int32(x^y)==0
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x^y) == 0) {
- break
- }
- v.reset(OpARMFlagEQ)
- return true
- }
- // match: (TEQconst (MOVWconst [x]) [y])
- // cond: int32(x^y)<0
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x^y) < 0) {
- break
- }
- v.reset(OpARMFlagLT_UGT)
- return true
- }
- // match: (TEQconst (MOVWconst [x]) [y])
- // cond: int32(x^y)>0
- // result: (FlagGT_UGT)
+ // result: (FlagConstant [logicFlags32(x^y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- x := v_0.AuxInt
- if !(int32(x^y) > 0) {
- break
- }
- v.reset(OpARMFlagGT_UGT)
+ x := auxIntToInt32(v_0.AuxInt)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(logicFlags32(x ^ y))
return true
}
return false
@@ -12716,48 +12101,15 @@ func rewriteValueARM_OpARMTST(v *Value) bool {
func rewriteValueARM_OpARMTSTconst(v *Value) bool {
v_0 := v.Args[0]
// match: (TSTconst (MOVWconst [x]) [y])
- // cond: int32(x&y)==0
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x&y) == 0) {
- break
- }
- v.reset(OpARMFlagEQ)
- return true
- }
- // match: (TSTconst (MOVWconst [x]) [y])
- // cond: int32(x&y)<0
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARMMOVWconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x&y) < 0) {
- break
- }
- v.reset(OpARMFlagLT_UGT)
- return true
- }
- // match: (TSTconst (MOVWconst [x]) [y])
- // cond: int32(x&y)>0
- // result: (FlagGT_UGT)
+ // result: (FlagConstant [logicFlags32(x&y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARMMOVWconst {
break
}
- x := v_0.AuxInt
- if !(int32(x&y) > 0) {
- break
- }
- v.reset(OpARMFlagGT_UGT)
+ x := auxIntToInt32(v_0.AuxInt)
+ v.reset(OpARMFlagConstant)
+ v.AuxInt = flagConstantToAuxInt(logicFlags32(x & y))
return true
}
return false
@@ -16617,36 +15969,27 @@ func rewriteValueARM_OpZeromask(v *Value) bool {
func rewriteBlockARM(b *Block) bool {
switch b.Kind {
case BlockARMEQ:
- // match: (EQ (FlagEQ) yes no)
+ // match: (EQ (FlagConstant [fc]) yes no)
+ // cond: fc.eq()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (EQ (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (EQ (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (EQ (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.eq()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (EQ (FlagGT_UGT) yes no)
+ // match: (EQ (FlagConstant [fc]) yes no)
+ // cond: !fc.eq()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.eq()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -17472,38 +16815,31 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMGE:
- // match: (GE (FlagEQ) yes no)
+ // match: (GE (FlagConstant [fc]) yes no)
+ // cond: fc.ge()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (GE (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ge()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (GE (FlagLT_UGT) yes no)
+ // match: (GE (FlagConstant [fc]) yes no)
+ // cond: !fc.ge()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ge()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (GE (FlagGT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (GE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
- b.Reset(BlockFirst)
- return true
- }
// match: (GE (InvertFlags cmp) yes no)
// result: (LE cmp yes no)
for b.Controls[0].Op == OpARMInvertFlags {
@@ -17514,7 +16850,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (GE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
- // result: (GE (CMP x y) yes no)
+ // result: (GEnoov (CMP x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17531,12 +16867,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(MULS x y a)) yes no)
// cond: l.Uses==1
- // result: (GE (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17556,12 +16892,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GE (CMPconst [c] x) yes no)
+ // result: (GEnoov (CMPconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17579,12 +16915,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftLL x y [c]) yes no)
+ // result: (GEnoov (CMPshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17603,12 +16939,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftRL x y [c]) yes no)
+ // result: (GEnoov (CMPshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17627,12 +16963,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftRA x y [c]) yes no)
+ // result: (GEnoov (CMPshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17651,12 +16987,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftLLreg x y z) yes no)
+ // result: (GEnoov (CMPshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17674,12 +17010,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftRLreg x y z) yes no)
+ // result: (GEnoov (CMPshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17697,12 +17033,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMPshiftRAreg x y z) yes no)
+ // result: (GEnoov (CMPshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17720,12 +17056,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADD x y)) yes no)
// cond: l.Uses==1
- // result: (GE (CMN x y) yes no)
+ // result: (GEnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17746,14 +17082,14 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
break
}
// match: (GE (CMPconst [0] l:(MULA x y a)) yes no)
// cond: l.Uses==1
- // result: (GE (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17773,12 +17109,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GE (CMNconst [c] x) yes no)
+ // result: (GEnoov (CMNconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17796,12 +17132,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftLL x y [c]) yes no)
+ // result: (GEnoov (CMNshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17820,12 +17156,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftRL x y [c]) yes no)
+ // result: (GEnoov (CMNshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17844,12 +17180,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftRA x y [c]) yes no)
+ // result: (GEnoov (CMNshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17868,12 +17204,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftLLreg x y z) yes no)
+ // result: (GEnoov (CMNshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17891,12 +17227,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftRLreg x y z) yes no)
+ // result: (GEnoov (CMNshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17914,12 +17250,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GE (CMNshiftRAreg x y z) yes no)
+ // result: (GEnoov (CMNshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -17937,7 +17273,7 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGE, v0)
+ b.resetWithControl(BlockARMGEnoov, v0)
return true
}
// match: (GE (CMPconst [0] l:(AND x y)) yes no)
@@ -18324,38 +17660,64 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGE, v0)
return true
}
- case BlockARMGT:
- // match: (GT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagEQ {
+ case BlockARMGEnoov:
+ // match: (GEnoov (FlagConstant [fc]) yes no)
+ // cond: fc.geNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.geNoov()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (GT (FlagLT_ULT) yes no)
+ // match: (GEnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.geNoov()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.geNoov()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (GT (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
+ // match: (GEnoov (InvertFlags cmp) yes no)
+ // result: (LEnoov cmp yes no)
+ for b.Controls[0].Op == OpARMInvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARMLEnoov, cmp)
return true
}
- // match: (GT (FlagGT_ULT) yes no)
+ case BlockARMGT:
+ // match: (GT (FlagConstant [fc]) yes no)
+ // cond: fc.gt()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.gt()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (GT (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ // match: (GT (FlagConstant [fc]) yes no)
+ // cond: !fc.gt()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.gt()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
// match: (GT (InvertFlags cmp) yes no)
@@ -18368,7 +17730,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (GT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
- // result: (GT (CMP x y) yes no)
+ // result: (GTnoov (CMP x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18385,12 +17747,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(MULS x y a)) yes no)
// cond: l.Uses==1
- // result: (GT (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18410,12 +17772,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GT (CMPconst [c] x) yes no)
+ // result: (GTnoov (CMPconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18433,12 +17795,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftLL x y [c]) yes no)
+ // result: (GTnoov (CMPshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18457,12 +17819,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftRL x y [c]) yes no)
+ // result: (GTnoov (CMPshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18481,12 +17843,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftRA x y [c]) yes no)
+ // result: (GTnoov (CMPshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18505,12 +17867,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftLLreg x y z) yes no)
+ // result: (GTnoov (CMPshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18528,12 +17890,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftRLreg x y z) yes no)
+ // result: (GTnoov (CMPshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18551,12 +17913,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMPshiftRAreg x y z) yes no)
+ // result: (GTnoov (CMPshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18574,12 +17936,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADD x y)) yes no)
// cond: l.Uses==1
- // result: (GT (CMN x y) yes no)
+ // result: (GTnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18600,14 +17962,14 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
break
}
// match: (GT (CMPconst [0] l:(ADDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (GT (CMNconst [c] x) yes no)
+ // result: (GTnoov (CMNconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18625,12 +17987,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftLL x y [c]) yes no)
+ // result: (GTnoov (CMNshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18649,12 +18011,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftRL x y [c]) yes no)
+ // result: (GTnoov (CMNshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18673,12 +18035,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftRA x y [c]) yes no)
+ // result: (GTnoov (CMNshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18697,12 +18059,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftLLreg x y z) yes no)
+ // result: (GTnoov (CMNshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18720,12 +18082,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftRLreg x y z) yes no)
+ // result: (GTnoov (CMNshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18743,12 +18105,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (GT (CMNshiftRAreg x y z) yes no)
+ // result: (GTnoov (CMNshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18766,7 +18128,7 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(AND x y)) yes no)
@@ -18799,7 +18161,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (GT (CMPconst [0] l:(MULA x y a)) yes no)
// cond: l.Uses==1
- // result: (GT (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -18819,7 +18181,7 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMGT, v0)
+ b.resetWithControl(BlockARMGTnoov, v0)
return true
}
// match: (GT (CMPconst [0] l:(ANDconst [c] x)) yes no)
@@ -19178,6 +18540,40 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMGT, v0)
return true
}
+ case BlockARMGTnoov:
+ // match: (GTnoov (FlagConstant [fc]) yes no)
+ // cond: fc.gtNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.gtNoov()) {
+ break
+ }
+ b.Reset(BlockFirst)
+ return true
+ }
+ // match: (GTnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.gtNoov()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.gtNoov()) {
+ break
+ }
+ b.Reset(BlockFirst)
+ b.swapSuccessors()
+ return true
+ }
+ // match: (GTnoov (InvertFlags cmp) yes no)
+ // result: (LTnoov cmp yes no)
+ for b.Controls[0].Op == OpARMInvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARMLTnoov, cmp)
+ return true
+ }
case BlockIf:
// match: (If (Equal cc) yes no)
// result: (EQ cc yes no)
@@ -19270,34 +18666,27 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMLE:
- // match: (LE (FlagEQ) yes no)
+ // match: (LE (FlagConstant [fc]) yes no)
+ // cond: fc.le()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (LE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (LE (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (LE (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.le()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LE (FlagGT_UGT) yes no)
+ // match: (LE (FlagConstant [fc]) yes no)
+ // cond: !fc.le()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.le()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -19312,7 +18701,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (LE (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
- // result: (LE (CMP x y) yes no)
+ // result: (LEnoov (CMP x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19329,12 +18718,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(MULS x y a)) yes no)
// cond: l.Uses==1
- // result: (LE (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19354,12 +18743,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LE (CMPconst [c] x) yes no)
+ // result: (LEnoov (CMPconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19377,12 +18766,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftLL x y [c]) yes no)
+ // result: (LEnoov (CMPshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19401,12 +18790,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftRL x y [c]) yes no)
+ // result: (LEnoov (CMPshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19425,12 +18814,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftRA x y [c]) yes no)
+ // result: (LEnoov (CMPshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19449,12 +18838,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftLLreg x y z) yes no)
+ // result: (LEnoov (CMPshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19472,12 +18861,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftRLreg x y z) yes no)
+ // result: (LEnoov (CMPshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19495,12 +18884,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMPshiftRAreg x y z) yes no)
+ // result: (LEnoov (CMPshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19518,12 +18907,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADD x y)) yes no)
// cond: l.Uses==1
- // result: (LE (CMN x y) yes no)
+ // result: (LEnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19544,14 +18933,14 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
break
}
// match: (LE (CMPconst [0] l:(MULA x y a)) yes no)
// cond: l.Uses==1
- // result: (LE (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19571,12 +18960,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LE (CMNconst [c] x) yes no)
+ // result: (LEnoov (CMNconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19594,12 +18983,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftLL x y [c]) yes no)
+ // result: (LEnoov (CMNshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19618,12 +19007,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftRL x y [c]) yes no)
+ // result: (LEnoov (CMNshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19642,12 +19031,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftRA x y [c]) yes no)
+ // result: (LEnoov (CMNshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19666,12 +19055,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftLLreg x y z) yes no)
+ // result: (LEnoov (CMNshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19689,12 +19078,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftRLreg x y z) yes no)
+ // result: (LEnoov (CMNshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19712,12 +19101,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LE (CMNshiftRAreg x y z) yes no)
+ // result: (LEnoov (CMNshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -19735,7 +19124,7 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLE, v0)
+ b.resetWithControl(BlockARMLEnoov, v0)
return true
}
// match: (LE (CMPconst [0] l:(AND x y)) yes no)
@@ -20122,36 +19511,62 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLE, v0)
return true
}
- case BlockARMLT:
- // match: (LT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagEQ {
+ case BlockARMLEnoov:
+ // match: (LEnoov (FlagConstant [fc]) yes no)
+ // cond: fc.leNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.leNoov()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LT (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
+ // match: (LEnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.leNoov()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.leNoov()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
- // match: (LT (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
+ // match: (LEnoov (InvertFlags cmp) yes no)
+ // result: (GEnoov cmp yes no)
+ for b.Controls[0].Op == OpARMInvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARMGEnoov, cmp)
return true
}
- // match: (LT (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ case BlockARMLT:
+ // match: (LT (FlagConstant [fc]) yes no)
+ // cond: fc.lt()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.lt()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LT (FlagGT_UGT) yes no)
+ // match: (LT (FlagConstant [fc]) yes no)
+ // cond: !fc.lt()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.lt()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -20166,7 +19581,7 @@ func rewriteBlockARM(b *Block) bool {
}
// match: (LT (CMPconst [0] l:(SUB x y)) yes no)
// cond: l.Uses==1
- // result: (LT (CMP x y) yes no)
+ // result: (LTnoov (CMP x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20183,12 +19598,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMP, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(MULS x y a)) yes no)
// cond: l.Uses==1
- // result: (LT (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20208,12 +19623,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LT (CMPconst [c] x) yes no)
+ // result: (LTnoov (CMPconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20231,12 +19646,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftLL x y [c]) yes no)
+ // result: (LTnoov (CMPshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20255,12 +19670,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftRL x y [c]) yes no)
+ // result: (LTnoov (CMPshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20279,12 +19694,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftRA x y [c]) yes no)
+ // result: (LTnoov (CMPshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20303,12 +19718,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftLLreg x y z) yes no)
+ // result: (LTnoov (CMPshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20326,12 +19741,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftRLreg x y z) yes no)
+ // result: (LTnoov (CMPshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20349,12 +19764,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMPshiftRAreg x y z) yes no)
+ // result: (LTnoov (CMPshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20372,12 +19787,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMPshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADD x y)) yes no)
// cond: l.Uses==1
- // result: (LT (CMN x y) yes no)
+ // result: (LTnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20398,14 +19813,14 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
break
}
// match: (LT (CMPconst [0] l:(MULA x y a)) yes no)
// cond: l.Uses==1
- // result: (LT (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20425,12 +19840,12 @@ func rewriteBlockARM(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARMMUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDconst [c] x)) yes no)
// cond: l.Uses==1
- // result: (LT (CMNconst [c] x) yes no)
+ // result: (LTnoov (CMNconst [c] x) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20448,12 +19863,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNconst, types.TypeFlags)
v0.AuxInt = c
v0.AddArg(x)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftLL x y [c]) yes no)
+ // result: (LTnoov (CMNshiftLL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20472,12 +19887,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftRL x y [c]) yes no)
+ // result: (LTnoov (CMNshiftRL x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20496,12 +19911,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRL, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftRA x y [c]) yes no)
+ // result: (LTnoov (CMNshiftRA x y [c]) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20520,12 +19935,12 @@ func rewriteBlockARM(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRA, types.TypeFlags)
v0.AuxInt = c
v0.AddArg2(x, y)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftLLreg x y z) yes no)
+ // result: (LTnoov (CMNshiftLLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20543,12 +19958,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftLLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftRLreg x y z) yes no)
+ // result: (LTnoov (CMNshiftRLreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20566,12 +19981,12 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRLreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no)
// cond: l.Uses==1
- // result: (LT (CMNshiftRAreg x y z) yes no)
+ // result: (LTnoov (CMNshiftRAreg x y z) yes no)
for b.Controls[0].Op == OpARMCMPconst {
v_0 := b.Controls[0]
if v_0.AuxInt != 0 {
@@ -20589,7 +20004,7 @@ func rewriteBlockARM(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARMCMNshiftRAreg, types.TypeFlags)
v0.AddArg3(x, y, z)
- b.resetWithControl(BlockARMLT, v0)
+ b.resetWithControl(BlockARMLTnoov, v0)
return true
}
// match: (LT (CMPconst [0] l:(AND x y)) yes no)
@@ -20976,6 +20391,40 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMLT, v0)
return true
}
+ case BlockARMLTnoov:
+ // match: (LTnoov (FlagConstant [fc]) yes no)
+ // cond: fc.ltNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ltNoov()) {
+ break
+ }
+ b.Reset(BlockFirst)
+ return true
+ }
+ // match: (LTnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.ltNoov()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ltNoov()) {
+ break
+ }
+ b.Reset(BlockFirst)
+ b.swapSuccessors()
+ return true
+ }
+ // match: (LTnoov (InvertFlags cmp) yes no)
+ // result: (GTnoov cmp yes no)
+ for b.Controls[0].Op == OpARMInvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARMGTnoov, cmp)
+ return true
+ }
case BlockARMNE:
// match: (NE (CMPconst [0] (Equal cc)) yes no)
// result: (EQ cc yes no)
@@ -21127,35 +20576,29 @@ func rewriteBlockARM(b *Block) bool {
b.resetWithControl(BlockARMUGE, cc)
return true
}
- // match: (NE (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (NE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (NE (FlagLT_UGT) yes no)
+ // match: (NE (FlagConstant [fc]) yes no)
+ // cond: fc.ne()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (NE (FlagGT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ne()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (NE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ // match: (NE (FlagConstant [fc]) yes no)
+ // cond: !fc.ne()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ne()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
// match: (NE (InvertFlags cmp) yes no)
@@ -21979,38 +21422,31 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMUGE:
- // match: (UGE (FlagEQ) yes no)
+ // match: (UGE (FlagConstant [fc]) yes no)
+ // cond: fc.uge()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (UGE (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGE (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.uge()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (UGE (FlagGT_ULT) yes no)
+ // match: (UGE (FlagConstant [fc]) yes no)
+ // cond: !fc.uge()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.uge()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (UGE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
- b.Reset(BlockFirst)
- return true
- }
// match: (UGE (InvertFlags cmp) yes no)
// result: (ULE cmp yes no)
for b.Controls[0].Op == OpARMInvertFlags {
@@ -22020,39 +21456,31 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMUGT:
- // match: (UGT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGT (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGT (FlagLT_UGT) yes no)
+ // match: (UGT (FlagConstant [fc]) yes no)
+ // cond: fc.ugt()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ugt()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (UGT (FlagGT_ULT) yes no)
+ // match: (UGT (FlagConstant [fc]) yes no)
+ // cond: !fc.ugt()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ugt()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (UGT (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
- b.Reset(BlockFirst)
- return true
- }
// match: (UGT (InvertFlags cmp) yes no)
// result: (ULT cmp yes no)
for b.Controls[0].Op == OpARMInvertFlags {
@@ -22062,34 +21490,27 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMULE:
- // match: (ULE (FlagEQ) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULE (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULE (FlagGT_ULT) yes no)
+ // match: (ULE (FlagConstant [fc]) yes no)
+ // cond: fc.ule()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ule()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (ULE (FlagGT_UGT) yes no)
+ // match: (ULE (FlagConstant [fc]) yes no)
+ // cond: !fc.ule()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ule()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -22103,35 +21524,27 @@ func rewriteBlockARM(b *Block) bool {
return true
}
case BlockARMULT:
- // match: (ULT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULT (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARMFlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULT (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARMFlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULT (FlagGT_ULT) yes no)
+ // match: (ULT (FlagConstant [fc]) yes no)
+ // cond: fc.ult()
// result: (First yes no)
- for b.Controls[0].Op == OpARMFlagGT_ULT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ult()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (ULT (FlagGT_UGT) yes no)
+ // match: (ULT (FlagConstant [fc]) yes no)
+ // cond: !fc.ult()
// result: (First no yes)
- for b.Controls[0].Op == OpARMFlagGT_UGT {
+ for b.Controls[0].Op == OpARMFlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ult()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go
index d243ea9407..8e48b33628 100644
--- a/src/cmd/compile/internal/ssa/rewriteARM64.go
+++ b/src/cmd/compile/internal/ssa/rewriteARM64.go
@@ -2575,78 +2575,15 @@ func rewriteValueARM64_OpARM64CMNW(v *Value) bool {
func rewriteValueARM64_OpARM64CMNWconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMNWconst (MOVDconst [x]) [y])
- // cond: int32(x)==int32(-y)
- // result: (FlagEQ)
+ // result: (FlagConstant [addFlags32(int32(x),y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(int32(x) == int32(-y)) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (CMNWconst (MOVDconst [x]) [y])
- // cond: int32(x)<int32(-y) && uint32(x)<uint32(-y)
- // result: (FlagLT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(-y) && uint32(x) < uint32(-y)) {
- break
- }
- v.reset(OpARM64FlagLT_ULT)
- return true
- }
- // match: (CMNWconst (MOVDconst [x]) [y])
- // cond: int32(x)<int32(-y) && uint32(x)>uint32(-y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(-y) && uint32(x) > uint32(-y)) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (CMNWconst (MOVDconst [x]) [y])
- // cond: int32(x)>int32(-y) && uint32(x)<uint32(-y)
- // result: (FlagGT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(-y) && uint32(x) < uint32(-y)) {
- break
- }
- v.reset(OpARM64FlagGT_ULT)
- return true
- }
- // match: (CMNWconst (MOVDconst [x]) [y])
- // cond: int32(x)>int32(-y) && uint32(x)>uint32(-y)
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(-y) && uint32(x) > uint32(-y)) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(addFlags32(int32(x), y))
return true
}
return false
@@ -2654,78 +2591,15 @@ func rewriteValueARM64_OpARM64CMNWconst(v *Value) bool {
func rewriteValueARM64_OpARM64CMNconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMNconst (MOVDconst [x]) [y])
- // cond: int64(x)==int64(-y)
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x) == int64(-y)) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (CMNconst (MOVDconst [x]) [y])
- // cond: int64(x)<int64(-y) && uint64(x)<uint64(-y)
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [addFlags64(x,y)])
for {
- y := v.AuxInt
+ y := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(int64(x) < int64(-y) && uint64(x) < uint64(-y)) {
- break
- }
- v.reset(OpARM64FlagLT_ULT)
- return true
- }
- // match: (CMNconst (MOVDconst [x]) [y])
- // cond: int64(x)<int64(-y) && uint64(x)>uint64(-y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x) < int64(-y) && uint64(x) > uint64(-y)) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (CMNconst (MOVDconst [x]) [y])
- // cond: int64(x)>int64(-y) && uint64(x)<uint64(-y)
- // result: (FlagGT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x) > int64(-y) && uint64(x) < uint64(-y)) {
- break
- }
- v.reset(OpARM64FlagGT_ULT)
- return true
- }
- // match: (CMNconst (MOVDconst [x]) [y])
- // cond: int64(x)>int64(-y) && uint64(x)>uint64(-y)
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x) > int64(-y) && uint64(x) > uint64(-y)) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(addFlags64(x, y))
return true
}
return false
@@ -3062,100 +2936,39 @@ func rewriteValueARM64_OpARM64CMPW(v *Value) bool {
func rewriteValueARM64_OpARM64CMPWconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMPWconst (MOVDconst [x]) [y])
- // cond: int32(x)==int32(y)
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) == int32(y)) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (CMPWconst (MOVDconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)<uint32(y)
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags32(int32(x),y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(int32(x) < int32(y) && uint32(x) < uint32(y)) {
- break
- }
- v.reset(OpARM64FlagLT_ULT)
- return true
- }
- // match: (CMPWconst (MOVDconst [x]) [y])
- // cond: int32(x)<int32(y) && uint32(x)>uint32(y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) < int32(y) && uint32(x) > uint32(y)) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (CMPWconst (MOVDconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)<uint32(y)
- // result: (FlagGT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(y) && uint32(x) < uint32(y)) {
- break
- }
- v.reset(OpARM64FlagGT_ULT)
- return true
- }
- // match: (CMPWconst (MOVDconst [x]) [y])
- // cond: int32(x)>int32(y) && uint32(x)>uint32(y)
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x) > int32(y) && uint32(x) > uint32(y)) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags32(int32(x), y))
return true
}
// match: (CMPWconst (MOVBUreg _) [c])
- // cond: 0xff < int32(c)
- // result: (FlagLT_ULT)
+ // cond: 0xff < c
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- c := v.AuxInt
- if v_0.Op != OpARM64MOVBUreg || !(0xff < int32(c)) {
+ c := auxIntToInt32(v.AuxInt)
+ if v_0.Op != OpARM64MOVBUreg || !(0xff < c) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
// match: (CMPWconst (MOVHUreg _) [c])
- // cond: 0xffff < int32(c)
- // result: (FlagLT_ULT)
+ // cond: 0xffff < c
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- c := v.AuxInt
- if v_0.Op != OpARM64MOVHUreg || !(0xffff < int32(c)) {
+ c := auxIntToInt32(v.AuxInt)
+ if v_0.Op != OpARM64MOVHUreg || !(0xffff < c) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
return false
@@ -3163,141 +2976,83 @@ func rewriteValueARM64_OpARM64CMPWconst(v *Value) bool {
func rewriteValueARM64_OpARM64CMPconst(v *Value) bool {
v_0 := v.Args[0]
// match: (CMPconst (MOVDconst [x]) [y])
- // cond: x==y
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(x == y) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (CMPconst (MOVDconst [x]) [y])
- // cond: x<y && uint64(x)<uint64(y)
- // result: (FlagLT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(x < y && uint64(x) < uint64(y)) {
- break
- }
- v.reset(OpARM64FlagLT_ULT)
- return true
- }
- // match: (CMPconst (MOVDconst [x]) [y])
- // cond: x<y && uint64(x)>uint64(y)
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(x < y && uint64(x) > uint64(y)) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (CMPconst (MOVDconst [x]) [y])
- // cond: x>y && uint64(x)<uint64(y)
- // result: (FlagGT_ULT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(x > y && uint64(x) < uint64(y)) {
- break
- }
- v.reset(OpARM64FlagGT_ULT)
- return true
- }
- // match: (CMPconst (MOVDconst [x]) [y])
- // cond: x>y && uint64(x)>uint64(y)
- // result: (FlagGT_UGT)
+ // result: (FlagConstant [subFlags64(x,y)])
for {
- y := v.AuxInt
+ y := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(x > y && uint64(x) > uint64(y)) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(x, y))
return true
}
// match: (CMPconst (MOVBUreg _) [c])
// cond: 0xff < c
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- c := v.AuxInt
+ c := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVBUreg || !(0xff < c) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
// match: (CMPconst (MOVHUreg _) [c])
// cond: 0xffff < c
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- c := v.AuxInt
+ c := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVHUreg || !(0xffff < c) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
// match: (CMPconst (MOVWUreg _) [c])
// cond: 0xffffffff < c
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- c := v.AuxInt
+ c := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVWUreg || !(0xffffffff < c) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
// match: (CMPconst (ANDconst _ [m]) [n])
// cond: 0 <= m && m < n
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- n := v.AuxInt
+ n := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64ANDconst {
break
}
- m := v_0.AuxInt
+ m := auxIntToInt64(v_0.AuxInt)
if !(0 <= m && m < n) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
// match: (CMPconst (SRLconst _ [c]) [n])
// cond: 0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n)
- // result: (FlagLT_ULT)
+ // result: (FlagConstant [subFlags64(0,1)])
for {
- n := v.AuxInt
+ n := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64SRLconst {
break
}
- c := v_0.AuxInt
+ c := auxIntToInt64(v_0.AuxInt)
if !(0 <= n && 0 < c && c <= 63 && (1<<uint64(64-c)) <= uint64(n)) {
break
}
- v.reset(OpARM64FlagLT_ULT)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(subFlags64(0, 1))
return true
}
return false
@@ -3849,54 +3604,15 @@ func rewriteValueARM64_OpARM64EONshiftRL(v *Value) bool {
}
func rewriteValueARM64_OpARM64Equal(v *Value) bool {
v_0 := v.Args[0]
- // match: (Equal (FlagEQ))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (Equal (FlagLT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagLT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagGT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (Equal (FlagGT_UGT))
- // result: (MOVDconst [0])
+ // match: (Equal (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.eq())])
for {
- if v_0.Op != OpARM64FlagGT_UGT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
+ v.AuxInt = int64ToAuxInt(b2i(fc.eq()))
return true
}
// match: (Equal (InvertFlags x))
@@ -4866,54 +4582,15 @@ func rewriteValueARM64_OpARM64FSUBS(v *Value) bool {
}
func rewriteValueARM64_OpARM64GreaterEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterEqual (FlagEQ))
- // result: (MOVDconst [1])
+ // match: (GreaterEqual (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.ge())])
for {
- if v_0.Op != OpARM64FlagEQ {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqual (FlagLT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqual (FlagLT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqual (FlagGT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqual (FlagGT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
+ v.AuxInt = int64ToAuxInt(b2i(fc.ge()))
return true
}
// match: (GreaterEqual (InvertFlags x))
@@ -4946,54 +4623,15 @@ func rewriteValueARM64_OpARM64GreaterEqualF(v *Value) bool {
}
func rewriteValueARM64_OpARM64GreaterEqualU(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterEqualU (FlagEQ))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqualU (FlagLT_ULT))
- // result: (MOVDconst [0])
+ // match: (GreaterEqualU (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.uge())])
for {
- if v_0.Op != OpARM64FlagLT_ULT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqualU (FlagLT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterEqualU (FlagGT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterEqualU (FlagGT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
+ v.AuxInt = int64ToAuxInt(b2i(fc.uge()))
return true
}
// match: (GreaterEqualU (InvertFlags x))
@@ -5011,54 +4649,15 @@ func rewriteValueARM64_OpARM64GreaterEqualU(v *Value) bool {
}
func rewriteValueARM64_OpARM64GreaterThan(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterThan (FlagEQ))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagLT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagLT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThan (FlagGT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterThan (FlagGT_UGT))
- // result: (MOVDconst [1])
+ // match: (GreaterThan (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.gt())])
for {
- if v_0.Op != OpARM64FlagGT_UGT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
+ v.AuxInt = int64ToAuxInt(b2i(fc.gt()))
return true
}
// match: (GreaterThan (InvertFlags x))
@@ -5091,54 +4690,15 @@ func rewriteValueARM64_OpARM64GreaterThanF(v *Value) bool {
}
func rewriteValueARM64_OpARM64GreaterThanU(v *Value) bool {
v_0 := v.Args[0]
- // match: (GreaterThanU (FlagEQ))
- // result: (MOVDconst [0])
+ // match: (GreaterThanU (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.ugt())])
for {
- if v_0.Op != OpARM64FlagEQ {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagLT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagLT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (GreaterThanU (FlagGT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (GreaterThanU (FlagGT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
+ v.AuxInt = int64ToAuxInt(b2i(fc.ugt()))
return true
}
// match: (GreaterThanU (InvertFlags x))
@@ -5156,54 +4716,15 @@ func rewriteValueARM64_OpARM64GreaterThanU(v *Value) bool {
}
func rewriteValueARM64_OpARM64LessEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessEqual (FlagEQ))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagLT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagLT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqual (FlagGT_ULT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessEqual (FlagGT_UGT))
- // result: (MOVDconst [0])
+ // match: (LessEqual (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.le())])
for {
- if v_0.Op != OpARM64FlagGT_UGT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
+ v.AuxInt = int64ToAuxInt(b2i(fc.le()))
return true
}
// match: (LessEqual (InvertFlags x))
@@ -5236,54 +4757,15 @@ func rewriteValueARM64_OpARM64LessEqualF(v *Value) bool {
}
func rewriteValueARM64_OpARM64LessEqualU(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessEqualU (FlagEQ))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagLT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagLT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessEqualU (FlagGT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessEqualU (FlagGT_UGT))
- // result: (MOVDconst [0])
+ // match: (LessEqualU (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.ule())])
for {
- if v_0.Op != OpARM64FlagGT_UGT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
+ v.AuxInt = int64ToAuxInt(b2i(fc.ule()))
return true
}
// match: (LessEqualU (InvertFlags x))
@@ -5301,54 +4783,15 @@ func rewriteValueARM64_OpARM64LessEqualU(v *Value) bool {
}
func rewriteValueARM64_OpARM64LessThan(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessThan (FlagEQ))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThan (FlagLT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThan (FlagLT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThan (FlagGT_ULT))
- // result: (MOVDconst [0])
+ // match: (LessThan (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.lt())])
for {
- if v_0.Op != OpARM64FlagGT_ULT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThan (FlagGT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
+ v.AuxInt = int64ToAuxInt(b2i(fc.lt()))
return true
}
// match: (LessThan (InvertFlags x))
@@ -5381,54 +4824,15 @@ func rewriteValueARM64_OpARM64LessThanF(v *Value) bool {
}
func rewriteValueARM64_OpARM64LessThanU(v *Value) bool {
v_0 := v.Args[0]
- // match: (LessThanU (FlagEQ))
- // result: (MOVDconst [0])
+ // match: (LessThanU (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.ult())])
for {
- if v_0.Op != OpARM64FlagEQ {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThanU (FlagLT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThanU (FlagLT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (LessThanU (FlagGT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (LessThanU (FlagGT_UGT))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
+ v.AuxInt = int64ToAuxInt(b2i(fc.ult()))
return true
}
// match: (LessThanU (InvertFlags x))
@@ -15447,54 +14851,15 @@ func rewriteValueARM64_OpARM64NEGshiftRL(v *Value) bool {
}
func rewriteValueARM64_OpARM64NotEqual(v *Value) bool {
v_0 := v.Args[0]
- // match: (NotEqual (FlagEQ))
- // result: (MOVDconst [0])
- for {
- if v_0.Op != OpARM64FlagEQ {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 0
- return true
- }
- // match: (NotEqual (FlagLT_ULT))
- // result: (MOVDconst [1])
+ // match: (NotEqual (FlagConstant [fc]))
+ // result: (MOVDconst [b2i(fc.ne())])
for {
- if v_0.Op != OpARM64FlagLT_ULT {
+ if v_0.Op != OpARM64FlagConstant {
break
}
+ fc := auxIntToFlagConstant(v_0.AuxInt)
v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagLT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagLT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagGT_ULT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_ULT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
- return true
- }
- // match: (NotEqual (FlagGT_UGT))
- // result: (MOVDconst [1])
- for {
- if v_0.Op != OpARM64FlagGT_UGT {
- break
- }
- v.reset(OpARM64MOVDconst)
- v.AuxInt = 1
+ v.AuxInt = int64ToAuxInt(b2i(fc.ne()))
return true
}
// match: (NotEqual (InvertFlags x))
@@ -20709,48 +20074,15 @@ func rewriteValueARM64_OpARM64TSTW(v *Value) bool {
func rewriteValueARM64_OpARM64TSTWconst(v *Value) bool {
v_0 := v.Args[0]
// match: (TSTWconst (MOVDconst [x]) [y])
- // cond: int32(x&y)==0
- // result: (FlagEQ)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x&y) == 0) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (TSTWconst (MOVDconst [x]) [y])
- // cond: int32(x&y)<0
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int32(x&y) < 0) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (TSTWconst (MOVDconst [x]) [y])
- // cond: int32(x&y)>0
- // result: (FlagGT_UGT)
+ // result: (FlagConstant [logicFlags32(int32(x)&y)])
for {
- y := v.AuxInt
+ y := auxIntToInt32(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(int32(x&y) > 0) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(logicFlags32(int32(x) & y))
return true
}
return false
@@ -20758,48 +20090,15 @@ func rewriteValueARM64_OpARM64TSTWconst(v *Value) bool {
func rewriteValueARM64_OpARM64TSTconst(v *Value) bool {
v_0 := v.Args[0]
// match: (TSTconst (MOVDconst [x]) [y])
- // cond: int64(x&y)==0
- // result: (FlagEQ)
+ // result: (FlagConstant [logicFlags64(x&y)])
for {
- y := v.AuxInt
+ y := auxIntToInt64(v.AuxInt)
if v_0.Op != OpARM64MOVDconst {
break
}
- x := v_0.AuxInt
- if !(int64(x&y) == 0) {
- break
- }
- v.reset(OpARM64FlagEQ)
- return true
- }
- // match: (TSTconst (MOVDconst [x]) [y])
- // cond: int64(x&y)<0
- // result: (FlagLT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x&y) < 0) {
- break
- }
- v.reset(OpARM64FlagLT_UGT)
- return true
- }
- // match: (TSTconst (MOVDconst [x]) [y])
- // cond: int64(x&y)>0
- // result: (FlagGT_UGT)
- for {
- y := v.AuxInt
- if v_0.Op != OpARM64MOVDconst {
- break
- }
- x := v_0.AuxInt
- if !(int64(x&y) > 0) {
- break
- }
- v.reset(OpARM64FlagGT_UGT)
+ x := auxIntToInt64(v_0.AuxInt)
+ v.reset(OpARM64FlagConstant)
+ v.AuxInt = flagConstantToAuxInt(logicFlags64(x & y))
return true
}
return false
@@ -26253,36 +25552,27 @@ func rewriteBlockARM64(b *Block) bool {
b.AuxInt = int64ToAuxInt(int64(ntz64(int64(uint32(c)))))
return true
}
- // match: (EQ (FlagEQ) yes no)
+ // match: (EQ (FlagConstant [fc]) yes no)
+ // cond: fc.eq()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (EQ (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (EQ (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (EQ (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.eq()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (EQ (FlagGT_UGT) yes no)
+ // match: (EQ (FlagConstant [fc]) yes no)
+ // cond: !fc.eq()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.eq()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -26436,7 +25726,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (GE (CMPconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (GE (CMNconst [c] y) yes no)
+ // result: (GEnoov (CMNconst [c] y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26454,12 +25744,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNconst, types.TypeFlags)
v0.AuxInt = int64ToAuxInt(c)
v0.AddArg(y)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPWconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (GE (CMNWconst [int32(c)] y) yes no)
+ // result: (GEnoov (CMNWconst [int32(c)] y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26477,12 +25767,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNWconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(int32(c))
v0.AddArg(y)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (GE (CMN x y) yes no)
+ // result: (GEnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26503,14 +25793,14 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
break
}
// match: (GE (CMPWconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (GE (CMNW x y) yes no)
+ // result: (GEnoov (CMNW x y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26531,7 +25821,7 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
break
@@ -26578,7 +25868,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (GE (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
- // result: (GE (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26598,12 +25888,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPconst [0] z:(MSUB a x y)) yes no)
// cond: z.Uses==1
- // result: (GE (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26623,12 +25913,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPWconst [0] z:(MADDW a x y)) yes no)
// cond: z.Uses==1
- // result: (GE (CMNW a (MULW <x.Type> x y)) yes no)
+ // result: (GEnoov (CMNW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26648,12 +25938,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPWconst [0] z:(MSUBW a x y)) yes no)
// cond: z.Uses==1
- // result: (GE (CMPW a (MULW <x.Type> x y)) yes no)
+ // result: (GEnoov (CMPW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26673,7 +25963,7 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GE, v0)
+ b.resetWithControl(BlockARM64GEnoov, v0)
return true
}
// match: (GE (CMPWconst [0] x) yes no)
@@ -26700,44 +25990,71 @@ func rewriteBlockARM64(b *Block) bool {
b.AuxInt = int64ToAuxInt(63)
return true
}
- // match: (GE (FlagEQ) yes no)
+ // match: (GE (FlagConstant [fc]) yes no)
+ // cond: fc.ge()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagEQ {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ge()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (GE (FlagLT_ULT) yes no)
+ // match: (GE (FlagConstant [fc]) yes no)
+ // cond: !fc.ge()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ge()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (GE (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
+ // match: (GE (InvertFlags cmp) yes no)
+ // result: (LE cmp yes no)
+ for b.Controls[0].Op == OpARM64InvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARM64LE, cmp)
return true
}
- // match: (GE (FlagGT_ULT) yes no)
+ case BlockARM64GEnoov:
+ // match: (GEnoov (FlagConstant [fc]) yes no)
+ // cond: fc.geNoov()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.geNoov()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (GE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ // match: (GEnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.geNoov()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.geNoov()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
- // match: (GE (InvertFlags cmp) yes no)
- // result: (LE cmp yes no)
+ // match: (GEnoov (InvertFlags cmp) yes no)
+ // result: (LEnoov cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
- b.resetWithControl(BlockARM64LE, cmp)
+ b.resetWithControl(BlockARM64LEnoov, cmp)
return true
}
case BlockARM64GT:
@@ -26845,7 +26162,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (GT (CMPconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (GT (CMNconst [c] y) yes no)
+ // result: (GTnoov (CMNconst [c] y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26863,12 +26180,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNconst, types.TypeFlags)
v0.AuxInt = int64ToAuxInt(c)
v0.AddArg(y)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
// match: (GT (CMPWconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (GT (CMNWconst [int32(c)] y) yes no)
+ // result: (GTnoov (CMNWconst [int32(c)] y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26886,12 +26203,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNWconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(int32(c))
v0.AddArg(y)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
// match: (GT (CMPconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (GT (CMN x y) yes no)
+ // result: (GTnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -26912,14 +26229,14 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
break
}
// match: (GT (CMPWconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (GT (CMNW x y) yes no)
+ // result: (GTnoov (CMNW x y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -26940,7 +26257,7 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
break
@@ -26987,7 +26304,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (GT (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
- // result: (GT (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27007,12 +26324,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
// match: (GT (CMPconst [0] z:(MSUB a x y)) yes no)
// cond: z.Uses==1
- // result: (GT (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27032,12 +26349,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
// match: (GT (CMPWconst [0] z:(MADDW a x y)) yes no)
// cond: z.Uses==1
- // result: (GT (CMNW a (MULW <x.Type> x y)) yes no)
+ // result: (GTnoov (CMNW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27057,12 +26374,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
// match: (GT (CMPWconst [0] z:(MSUBW a x y)) yes no)
// cond: z.Uses==1
- // result: (GT (CMPW a (MULW <x.Type> x y)) yes no)
+ // result: (GTnoov (CMPW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27082,48 +26399,74 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64GT, v0)
+ b.resetWithControl(BlockARM64GTnoov, v0)
return true
}
- // match: (GT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagEQ {
+ // match: (GT (FlagConstant [fc]) yes no)
+ // cond: fc.gt()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.gt()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (GT (FlagLT_ULT) yes no)
+ // match: (GT (FlagConstant [fc]) yes no)
+ // cond: !fc.gt()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.gt()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (GT (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
+ // match: (GT (InvertFlags cmp) yes no)
+ // result: (LT cmp yes no)
+ for b.Controls[0].Op == OpARM64InvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARM64LT, cmp)
return true
}
- // match: (GT (FlagGT_ULT) yes no)
+ case BlockARM64GTnoov:
+ // match: (GTnoov (FlagConstant [fc]) yes no)
+ // cond: fc.gtNoov()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.gtNoov()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (GT (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ // match: (GTnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.gtNoov()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.gtNoov()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
- // match: (GT (InvertFlags cmp) yes no)
- // result: (LT cmp yes no)
+ // match: (GTnoov (InvertFlags cmp) yes no)
+ // result: (LTnoov cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
- b.resetWithControl(BlockARM64LT, cmp)
+ b.resetWithControl(BlockARM64LTnoov, cmp)
return true
}
case BlockIf:
@@ -27351,7 +26694,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (LE (CMPconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (LE (CMNconst [c] y) yes no)
+ // result: (LEnoov (CMNconst [c] y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27369,12 +26712,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNconst, types.TypeFlags)
v0.AuxInt = int64ToAuxInt(c)
v0.AddArg(y)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
// match: (LE (CMPWconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (LE (CMNWconst [int32(c)] y) yes no)
+ // result: (LEnoov (CMNWconst [int32(c)] y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27392,12 +26735,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNWconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(int32(c))
v0.AddArg(y)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
// match: (LE (CMPconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (LE (CMN x y) yes no)
+ // result: (LEnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27418,14 +26761,14 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
break
}
// match: (LE (CMPWconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (LE (CMNW x y) yes no)
+ // result: (LEnoov (CMNW x y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27446,7 +26789,7 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
break
@@ -27493,7 +26836,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (LE (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
- // result: (LE (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27513,12 +26856,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
// match: (LE (CMPconst [0] z:(MSUB a x y)) yes no)
// cond: z.Uses==1
- // result: (LE (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27538,12 +26881,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
// match: (LE (CMPWconst [0] z:(MADDW a x y)) yes no)
// cond: z.Uses==1
- // result: (LE (CMNW a (MULW <x.Type> x y)) yes no)
+ // result: (LEnoov (CMNW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27563,12 +26906,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
// match: (LE (CMPWconst [0] z:(MSUBW a x y)) yes no)
// cond: z.Uses==1
- // result: (LE (CMPW a (MULW <x.Type> x y)) yes no)
+ // result: (LEnoov (CMPW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27588,47 +26931,74 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LE, v0)
+ b.resetWithControl(BlockARM64LEnoov, v0)
return true
}
- // match: (LE (FlagEQ) yes no)
+ // match: (LE (FlagConstant [fc]) yes no)
+ // cond: fc.le()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagEQ {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.le()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (LE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
+ // match: (LE (FlagConstant [fc]) yes no)
+ // cond: !fc.le()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.le()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
- // match: (LE (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
+ // match: (LE (InvertFlags cmp) yes no)
+ // result: (GE cmp yes no)
+ for b.Controls[0].Op == OpARM64InvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARM64GE, cmp)
return true
}
- // match: (LE (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ case BlockARM64LEnoov:
+ // match: (LEnoov (FlagConstant [fc]) yes no)
+ // cond: fc.leNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.leNoov()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LE (FlagGT_UGT) yes no)
+ // match: (LEnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.leNoov()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.leNoov()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (LE (InvertFlags cmp) yes no)
- // result: (GE cmp yes no)
+ // match: (LEnoov (InvertFlags cmp) yes no)
+ // result: (GEnoov cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
- b.resetWithControl(BlockARM64GE, cmp)
+ b.resetWithControl(BlockARM64GEnoov, cmp)
return true
}
case BlockARM64LT:
@@ -27736,7 +27106,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (LT (CMPconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (LT (CMNconst [c] y) yes no)
+ // result: (LTnoov (CMNconst [c] y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27754,12 +27124,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNconst, types.TypeFlags)
v0.AuxInt = int64ToAuxInt(c)
v0.AddArg(y)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPWconst [0] x:(ADDconst [c] y)) yes no)
// cond: x.Uses == 1
- // result: (LT (CMNWconst [int32(c)] y) yes no)
+ // result: (LTnoov (CMNWconst [int32(c)] y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27777,12 +27147,12 @@ func rewriteBlockARM64(b *Block) bool {
v0 := b.NewValue0(v_0.Pos, OpARM64CMNWconst, types.TypeFlags)
v0.AuxInt = int32ToAuxInt(int32(c))
v0.AddArg(y)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (LT (CMN x y) yes no)
+ // result: (LTnoov (CMN x y) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27803,14 +27173,14 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMN, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
break
}
// match: (LT (CMPWconst [0] z:(ADD x y)) yes no)
// cond: z.Uses == 1
- // result: (LT (CMNW x y) yes no)
+ // result: (LTnoov (CMNW x y) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27831,7 +27201,7 @@ func rewriteBlockARM64(b *Block) bool {
}
v0 := b.NewValue0(v_0.Pos, OpARM64CMNW, types.TypeFlags)
v0.AddArg2(x, y)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
break
@@ -27878,7 +27248,7 @@ func rewriteBlockARM64(b *Block) bool {
}
// match: (LT (CMPconst [0] z:(MADD a x y)) yes no)
// cond: z.Uses==1
- // result: (LT (CMN a (MUL <x.Type> x y)) yes no)
+ // result: (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27898,12 +27268,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPconst [0] z:(MSUB a x y)) yes no)
// cond: z.Uses==1
- // result: (LT (CMP a (MUL <x.Type> x y)) yes no)
+ // result: (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPconst {
v_0 := b.Controls[0]
if auxIntToInt64(v_0.AuxInt) != 0 {
@@ -27923,12 +27293,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MUL, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPWconst [0] z:(MADDW a x y)) yes no)
// cond: z.Uses==1
- // result: (LT (CMNW a (MULW <x.Type> x y)) yes no)
+ // result: (LTnoov (CMNW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27948,12 +27318,12 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPWconst [0] z:(MSUBW a x y)) yes no)
// cond: z.Uses==1
- // result: (LT (CMPW a (MULW <x.Type> x y)) yes no)
+ // result: (LTnoov (CMPW a (MULW <x.Type> x y)) yes no)
for b.Controls[0].Op == OpARM64CMPWconst {
v_0 := b.Controls[0]
if auxIntToInt32(v_0.AuxInt) != 0 {
@@ -27973,7 +27343,7 @@ func rewriteBlockARM64(b *Block) bool {
v1 := b.NewValue0(v_0.Pos, OpARM64MULW, x.Type)
v1.AddArg2(x, y)
v0.AddArg2(a, v1)
- b.resetWithControl(BlockARM64LT, v0)
+ b.resetWithControl(BlockARM64LTnoov, v0)
return true
}
// match: (LT (CMPWconst [0] x) yes no)
@@ -28000,45 +27370,71 @@ func rewriteBlockARM64(b *Block) bool {
b.AuxInt = int64ToAuxInt(63)
return true
}
- // match: (LT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagEQ {
+ // match: (LT (FlagConstant [fc]) yes no)
+ // cond: fc.lt()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.lt()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LT (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
+ // match: (LT (FlagConstant [fc]) yes no)
+ // cond: !fc.lt()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.lt()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
- // match: (LT (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
+ // match: (LT (InvertFlags cmp) yes no)
+ // result: (GT cmp yes no)
+ for b.Controls[0].Op == OpARM64InvertFlags {
+ v_0 := b.Controls[0]
+ cmp := v_0.Args[0]
+ b.resetWithControl(BlockARM64GT, cmp)
return true
}
- // match: (LT (FlagGT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ case BlockARM64LTnoov:
+ // match: (LTnoov (FlagConstant [fc]) yes no)
+ // cond: fc.ltNoov()
+ // result: (First yes no)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ltNoov()) {
+ break
+ }
b.Reset(BlockFirst)
- b.swapSuccessors()
return true
}
- // match: (LT (FlagGT_UGT) yes no)
+ // match: (LTnoov (FlagConstant [fc]) yes no)
+ // cond: !fc.ltNoov()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ltNoov()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (LT (InvertFlags cmp) yes no)
- // result: (GT cmp yes no)
+ // match: (LTnoov (InvertFlags cmp) yes no)
+ // result: (GTnoov cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
v_0 := b.Controls[0]
cmp := v_0.Args[0]
- b.resetWithControl(BlockARM64GT, cmp)
+ b.resetWithControl(BlockARM64GTnoov, cmp)
return true
}
case BlockARM64NE:
@@ -28436,35 +27832,29 @@ func rewriteBlockARM64(b *Block) bool {
b.AuxInt = int64ToAuxInt(int64(ntz64(int64(uint32(c)))))
return true
}
- // match: (NE (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (NE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (NE (FlagLT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (NE (FlagGT_ULT) yes no)
+ // match: (NE (FlagConstant [fc]) yes no)
+ // cond: fc.ne()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ne()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (NE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ // match: (NE (FlagConstant [fc]) yes no)
+ // cond: !fc.ne()
+ // result: (First no yes)
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ne()) {
+ break
+ }
b.Reset(BlockFirst)
+ b.swapSuccessors()
return true
}
// match: (NE (InvertFlags cmp) yes no)
@@ -28666,38 +28056,31 @@ func rewriteBlockARM64(b *Block) bool {
return true
}
case BlockARM64UGE:
- // match: (UGE (FlagEQ) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (UGE (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGE (FlagLT_UGT) yes no)
+ // match: (UGE (FlagConstant [fc]) yes no)
+ // cond: fc.uge()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.uge()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (UGE (FlagGT_ULT) yes no)
+ // match: (UGE (FlagConstant [fc]) yes no)
+ // cond: !fc.uge()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.uge()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (UGE (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
- b.Reset(BlockFirst)
- return true
- }
// match: (UGE (InvertFlags cmp) yes no)
// result: (ULE cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
@@ -28707,39 +28090,31 @@ func rewriteBlockARM64(b *Block) bool {
return true
}
case BlockARM64UGT:
- // match: (UGT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGT (FlagLT_ULT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (UGT (FlagLT_UGT) yes no)
+ // match: (UGT (FlagConstant [fc]) yes no)
+ // cond: fc.ugt()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ugt()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (UGT (FlagGT_ULT) yes no)
+ // match: (UGT (FlagConstant [fc]) yes no)
+ // cond: !fc.ugt()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ugt()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
}
- // match: (UGT (FlagGT_UGT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
- b.Reset(BlockFirst)
- return true
- }
// match: (UGT (InvertFlags cmp) yes no)
// result: (ULT cmp yes no)
for b.Controls[0].Op == OpARM64InvertFlags {
@@ -28749,34 +28124,27 @@ func rewriteBlockARM64(b *Block) bool {
return true
}
case BlockARM64ULE:
- // match: (ULE (FlagEQ) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULE (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULE (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULE (FlagGT_ULT) yes no)
+ // match: (ULE (FlagConstant [fc]) yes no)
+ // cond: fc.ule()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ule()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (ULE (FlagGT_UGT) yes no)
+ // match: (ULE (FlagConstant [fc]) yes no)
+ // cond: !fc.ule()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ule()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
@@ -28790,35 +28158,27 @@ func rewriteBlockARM64(b *Block) bool {
return true
}
case BlockARM64ULT:
- // match: (ULT (FlagEQ) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagEQ {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULT (FlagLT_ULT) yes no)
- // result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagLT_ULT {
- b.Reset(BlockFirst)
- return true
- }
- // match: (ULT (FlagLT_UGT) yes no)
- // result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagLT_UGT {
- b.Reset(BlockFirst)
- b.swapSuccessors()
- return true
- }
- // match: (ULT (FlagGT_ULT) yes no)
+ // match: (ULT (FlagConstant [fc]) yes no)
+ // cond: fc.ult()
// result: (First yes no)
- for b.Controls[0].Op == OpARM64FlagGT_ULT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(fc.ult()) {
+ break
+ }
b.Reset(BlockFirst)
return true
}
- // match: (ULT (FlagGT_UGT) yes no)
+ // match: (ULT (FlagConstant [fc]) yes no)
+ // cond: !fc.ult()
// result: (First no yes)
- for b.Controls[0].Op == OpARM64FlagGT_UGT {
+ for b.Controls[0].Op == OpARM64FlagConstant {
+ v_0 := b.Controls[0]
+ fc := auxIntToFlagConstant(v_0.AuxInt)
+ if !(!fc.ult()) {
+ break
+ }
b.Reset(BlockFirst)
b.swapSuccessors()
return true
diff --git a/src/cmd/compile/internal/ssa/rewriteCond_test.go b/src/cmd/compile/internal/ssa/rewriteCond_test.go
new file mode 100644
index 0000000000..2c26fdf142
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewriteCond_test.go
@@ -0,0 +1,597 @@
+// Copyright 2020 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 (
+ "math"
+ "math/rand"
+ "testing"
+)
+
+var (
+ x64 int64 = math.MaxInt64 - 2
+ x64b int64 = math.MaxInt64 - 2
+ x64c int64 = math.MaxInt64 - 2
+ y64 int64 = math.MinInt64 + 1
+ x32 int32 = math.MaxInt32 - 2
+ x32b int32 = math.MaxInt32 - 2
+ x32c int32 = math.MaxInt32 - 2
+ y32 int32 = math.MinInt32 + 1
+ one64 int64 = 1
+ one32 int32 = 1
+ v64 int64 = 11 // ensure it's not 2**n +/- 1
+ v64_n int64 = -11
+ v32 int32 = 11
+ v32_n int32 = -11
+ uv32 uint32 = 19
+ uz uint8 = 1 // for lowering to SLL/SRL/SRA
+)
+
+var crTests = []struct {
+ name string
+ tf func(t *testing.T)
+}{
+ {"AddConst64", testAddConst64},
+ {"AddConst32", testAddConst32},
+ {"AddVar64", testAddVar64},
+ {"AddVar32", testAddVar32},
+ {"MAddVar64", testMAddVar64},
+ {"MAddVar32", testMAddVar32},
+ {"MSubVar64", testMSubVar64},
+ {"MSubVar32", testMSubVar32},
+ {"AddShift32", testAddShift32},
+ {"SubShift32", testSubShift32},
+}
+
+var crBenches = []struct {
+ name string
+ bf func(b *testing.B)
+}{
+ {"SoloJump", benchSoloJump},
+ {"CombJump", benchCombJump},
+}
+
+// Test int32/int64's add/sub/madd/msub operations with boundary values to
+// ensure the optimization to 'comparing to zero' expressions of if-statements
+// yield expected results.
+// 32 rewriting rules are covered. At least two scenarios for "Canonicalize
+// the order of arguments to comparisons", which helps with CSE, are covered.
+// The tedious if-else structures are necessary to ensure all concerned rules
+// and machine code sequences are covered.
+// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
+func TestCondRewrite(t *testing.T) {
+ for _, test := range crTests {
+ t.Run(test.name, test.tf)
+ }
+}
+
+// Profile the aforementioned optimization from two angles:
+// SoloJump: generated branching code has one 'jump', for '<' and '>='
+// CombJump: generated branching code has two consecutive 'jump', for '<=' and '>'
+// We expect that 'CombJump' is generally on par with the non-optimized code, and
+// 'SoloJump' demonstrates some improvement.
+// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
+func BenchmarkCondRewrite(b *testing.B) {
+ for _, bench := range crBenches {
+ b.Run(bench.name, bench.bf)
+ }
+}
+
+// var +/- const
+func testAddConst64(t *testing.T) {
+ if x64+11 < 0 {
+ } else {
+ t.Errorf("'%#x + 11 < 0' failed", x64)
+ }
+
+ if x64+13 <= 0 {
+ } else {
+ t.Errorf("'%#x + 13 <= 0' failed", x64)
+ }
+
+ if y64-11 > 0 {
+ } else {
+ t.Errorf("'%#x - 11 > 0' failed", y64)
+ }
+
+ if y64-13 >= 0 {
+ } else {
+ t.Errorf("'%#x - 13 >= 0' failed", y64)
+ }
+
+ if x64+19 > 0 {
+ t.Errorf("'%#x + 19 > 0' failed", x64)
+ }
+
+ if x64+23 >= 0 {
+ t.Errorf("'%#x + 23 >= 0' failed", x64)
+ }
+
+ if y64-19 < 0 {
+ t.Errorf("'%#x - 19 < 0' failed", y64)
+ }
+
+ if y64-23 <= 0 {
+ t.Errorf("'%#x - 23 <= 0' failed", y64)
+ }
+}
+
+// 32-bit var +/- const
+func testAddConst32(t *testing.T) {
+ if x32+11 < 0 {
+ } else {
+ t.Errorf("'%#x + 11 < 0' failed", x32)
+ }
+
+ if x32+13 <= 0 {
+ } else {
+ t.Errorf("'%#x + 13 <= 0' failed", x32)
+ }
+
+ if y32-11 > 0 {
+ } else {
+ t.Errorf("'%#x - 11 > 0' failed", y32)
+ }
+
+ if y32-13 >= 0 {
+ } else {
+ t.Errorf("'%#x - 13 >= 0' failed", y32)
+ }
+
+ if x32+19 > 0 {
+ t.Errorf("'%#x + 19 > 0' failed", x32)
+ }
+
+ if x32+23 >= 0 {
+ t.Errorf("'%#x + 23 >= 0' failed", x32)
+ }
+
+ if y32-19 < 0 {
+ t.Errorf("'%#x - 19 < 0' failed", y32)
+ }
+
+ if y32-23 <= 0 {
+ t.Errorf("'%#x - 23 <= 0' failed", y32)
+ }
+}
+
+// var + var
+func testAddVar64(t *testing.T) {
+ if x64+v64 < 0 {
+ } else {
+ t.Errorf("'%#x + %#x < 0' failed", x64, v64)
+ }
+
+ if x64+v64 <= 0 {
+ } else {
+ t.Errorf("'%#x + %#x <= 0' failed", x64, v64)
+ }
+
+ if y64+v64_n > 0 {
+ } else {
+ t.Errorf("'%#x + %#x > 0' failed", y64, v64_n)
+ }
+
+ if y64+v64_n >= 0 {
+ } else {
+ t.Errorf("'%#x + %#x >= 0' failed", y64, v64_n)
+ }
+
+ if x64+v64 > 0 {
+ t.Errorf("'%#x + %#x > 0' failed", x64, v64)
+ }
+
+ if x64+v64 >= 0 {
+ t.Errorf("'%#x + %#x >= 0' failed", x64, v64)
+ }
+
+ if y64+v64_n < 0 {
+ t.Errorf("'%#x + %#x < 0' failed", y64, v64_n)
+ }
+
+ if y64+v64_n <= 0 {
+ t.Errorf("'%#x + %#x <= 0' failed", y64, v64_n)
+ }
+}
+
+// 32-bit var+var
+func testAddVar32(t *testing.T) {
+ if x32+v32 < 0 {
+ } else {
+ t.Errorf("'%#x + %#x < 0' failed", x32, v32)
+ }
+
+ if x32+v32 <= 0 {
+ } else {
+ t.Errorf("'%#x + %#x <= 0' failed", x32, v32)
+ }
+
+ if y32+v32_n > 0 {
+ } else {
+ t.Errorf("'%#x + %#x > 0' failed", y32, v32_n)
+ }
+
+ if y32+v32_n >= 0 {
+ } else {
+ t.Errorf("'%#x + %#x >= 0' failed", y32, v32_n)
+ }
+
+ if x32+v32 > 0 {
+ t.Errorf("'%#x + %#x > 0' failed", x32, v32)
+ }
+
+ if x32+v32 >= 0 {
+ t.Errorf("'%#x + %#x >= 0' failed", x32, v32)
+ }
+
+ if y32+v32_n < 0 {
+ t.Errorf("'%#x + %#x < 0' failed", y32, v32_n)
+ }
+
+ if y32+v32_n <= 0 {
+ t.Errorf("'%#x + %#x <= 0' failed", y32, v32_n)
+ }
+}
+
+// multiply-add
+func testMAddVar64(t *testing.T) {
+ if x64+v64*one64 < 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 < 0' failed", x64, v64)
+ }
+
+ if x64+v64*one64 <= 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 <= 0' failed", x64, v64)
+ }
+
+ if y64+v64_n*one64 > 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 > 0' failed", y64, v64_n)
+ }
+
+ if y64+v64_n*one64 >= 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 >= 0' failed", y64, v64_n)
+ }
+
+ if x64+v64*one64 > 0 {
+ t.Errorf("'%#x + %#x*1 > 0' failed", x64, v64)
+ }
+
+ if x64+v64*one64 >= 0 {
+ t.Errorf("'%#x + %#x*1 >= 0' failed", x64, v64)
+ }
+
+ if y64+v64_n*one64 < 0 {
+ t.Errorf("'%#x + %#x*1 < 0' failed", y64, v64_n)
+ }
+
+ if y64+v64_n*one64 <= 0 {
+ t.Errorf("'%#x + %#x*1 <= 0' failed", y64, v64_n)
+ }
+}
+
+// 32-bit multiply-add
+func testMAddVar32(t *testing.T) {
+ if x32+v32*one32 < 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 < 0' failed", x32, v32)
+ }
+
+ if x32+v32*one32 <= 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 <= 0' failed", x32, v32)
+ }
+
+ if y32+v32_n*one32 > 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 > 0' failed", y32, v32_n)
+ }
+
+ if y32+v32_n*one32 >= 0 {
+ } else {
+ t.Errorf("'%#x + %#x*1 >= 0' failed", y32, v32_n)
+ }
+
+ if x32+v32*one32 > 0 {
+ t.Errorf("'%#x + %#x*1 > 0' failed", x32, v32)
+ }
+
+ if x32+v32*one32 >= 0 {
+ t.Errorf("'%#x + %#x*1 >= 0' failed", x32, v32)
+ }
+
+ if y32+v32_n*one32 < 0 {
+ t.Errorf("'%#x + %#x*1 < 0' failed", y32, v32_n)
+ }
+
+ if y32+v32_n*one32 <= 0 {
+ t.Errorf("'%#x + %#x*1 <= 0' failed", y32, v32_n)
+ }
+}
+
+// multiply-sub
+func testMSubVar64(t *testing.T) {
+ if x64-v64_n*one64 < 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 < 0' failed", x64, v64_n)
+ }
+
+ if x64-v64_n*one64 <= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 <= 0' failed", x64, v64_n)
+ }
+
+ if y64-v64*one64 > 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 > 0' failed", y64, v64)
+ }
+
+ if y64-v64*one64 >= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", y64, v64)
+ }
+
+ if x64-v64_n*one64 > 0 {
+ t.Errorf("'%#x - %#x*1 > 0' failed", x64, v64_n)
+ }
+
+ if x64-v64_n*one64 >= 0 {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", x64, v64_n)
+ }
+
+ if y64-v64*one64 < 0 {
+ t.Errorf("'%#x - %#x*1 < 0' failed", y64, v64)
+ }
+
+ if y64-v64*one64 <= 0 {
+ t.Errorf("'%#x - %#x*1 <= 0' failed", y64, v64)
+ }
+
+ if x64-x64b*one64 < 0 {
+ t.Errorf("'%#x - %#x*1 < 0' failed", x64, x64b)
+ }
+
+ if x64-x64b*one64 >= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", x64, x64b)
+ }
+}
+
+// 32-bit multiply-sub
+func testMSubVar32(t *testing.T) {
+ if x32-v32_n*one32 < 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 < 0' failed", x32, v32_n)
+ }
+
+ if x32-v32_n*one32 <= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 <= 0' failed", x32, v32_n)
+ }
+
+ if y32-v32*one32 > 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 > 0' failed", y32, v32)
+ }
+
+ if y32-v32*one32 >= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", y32, v32)
+ }
+
+ if x32-v32_n*one32 > 0 {
+ t.Errorf("'%#x - %#x*1 > 0' failed", x32, v32_n)
+ }
+
+ if x32-v32_n*one32 >= 0 {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", x32, v32_n)
+ }
+
+ if y32-v32*one32 < 0 {
+ t.Errorf("'%#x - %#x*1 < 0' failed", y32, v32)
+ }
+
+ if y32-v32*one32 <= 0 {
+ t.Errorf("'%#x - %#x*1 <= 0' failed", y32, v32)
+ }
+
+ if x32-x32b*one32 < 0 {
+ t.Errorf("'%#x - %#x*1 < 0' failed", x32, x32b)
+ }
+
+ if x32-x32b*one32 >= 0 {
+ } else {
+ t.Errorf("'%#x - %#x*1 >= 0' failed", x32, x32b)
+ }
+}
+
+// 32-bit ADDshift, pick up 1~2 scenarios randomly for each condition
+func testAddShift32(t *testing.T) {
+ if x32+v32<<1 < 0 {
+ } else {
+ t.Errorf("'%#x + %#x<<%#x < 0' failed", x32, v32, 1)
+ }
+
+ if x32+v32>>1 <= 0 {
+ } else {
+ t.Errorf("'%#x + %#x>>%#x <= 0' failed", x32, v32, 1)
+ }
+
+ if x32+int32(uv32>>1) > 0 {
+ t.Errorf("'%#x + int32(%#x>>%#x) > 0' failed", x32, uv32, 1)
+ }
+
+ if x32+v32<<uz >= 0 {
+ t.Errorf("'%#x + %#x<<%#x >= 0' failed", x32, v32, uz)
+ }
+
+ if x32+v32>>uz > 0 {
+ t.Errorf("'%#x + %#x>>%#x > 0' failed", x32, v32, uz)
+ }
+
+ if x32+int32(uv32>>uz) < 0 {
+ } else {
+ t.Errorf("'%#x + int32(%#x>>%#x) < 0' failed", x32, uv32, uz)
+ }
+}
+
+// 32-bit SUBshift, pick up 1~2 scenarios randomly for each condition
+func testSubShift32(t *testing.T) {
+ if y32-v32<<1 > 0 {
+ } else {
+ t.Errorf("'%#x - %#x<<%#x > 0' failed", y32, v32, 1)
+ }
+
+ if y32-v32>>1 < 0 {
+ t.Errorf("'%#x - %#x>>%#x < 0' failed", y32, v32, 1)
+ }
+
+ if y32-int32(uv32>>1) >= 0 {
+ } else {
+ t.Errorf("'%#x - int32(%#x>>%#x) >= 0' failed", y32, uv32, 1)
+ }
+
+ if y32-v32<<uz < 0 {
+ t.Errorf("'%#x - %#x<<%#x < 0' failed", y32, v32, uz)
+ }
+
+ if y32-v32>>uz >= 0 {
+ } else {
+ t.Errorf("'%#x - %#x>>%#x >= 0' failed", y32, v32, uz)
+ }
+
+ if y32-int32(uv32>>uz) <= 0 {
+ t.Errorf("'%#x - int32(%#x>>%#x) <= 0' failed", y32, uv32, uz)
+ }
+}
+
+var rnd = rand.New(rand.NewSource(0))
+var sink int64
+
+func benchSoloJump(b *testing.B) {
+ r1 := x64
+ r2 := x64b
+ r3 := x64c
+ r4 := y64
+ d := rnd.Int63n(10)
+
+ // 6 out 10 conditions evaluate to true
+ for i := 0; i < b.N; i++ {
+ if r1+r2 < 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+r3 >= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+r2*one64 < 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r2+r3*one64 >= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1-r2*v64 >= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r3-r4*v64 < 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+11 < 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+13 >= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r4-17 < 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r4-19 >= 0 {
+ d *= 2
+ d /= 2
+ }
+ }
+ sink = d
+}
+
+func benchCombJump(b *testing.B) {
+ r1 := x64
+ r2 := x64b
+ r3 := x64c
+ r4 := y64
+ d := rnd.Int63n(10)
+
+ // 6 out 10 conditions evaluate to true
+ for i := 0; i < b.N; i++ {
+ if r1+r2 <= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+r3 > 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+r2*one64 <= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r2+r3*one64 > 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1-r2*v64 > 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r3-r4*v64 <= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+11 <= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r1+13 > 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r4-17 <= 0 {
+ d *= 2
+ d /= 2
+ }
+
+ if r4-19 > 0 {
+ d *= 2
+ d /= 2
+ }
+ }
+ sink = d
+}
diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go
index 0b798c6a72..37b75cc58a 100644
--- a/src/cmd/compile/internal/ssa/rewritePPC64.go
+++ b/src/cmd/compile/internal/ssa/rewritePPC64.go
@@ -2351,7 +2351,7 @@ func rewriteValuePPC64_OpLsh16x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2362,7 +2362,7 @@ func rewriteValuePPC64_OpLsh16x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -2552,7 +2552,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2563,7 +2563,7 @@ func rewriteValuePPC64_OpLsh32x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -2792,7 +2792,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SLDconst x [c])
+ // result: (SLDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -2803,7 +2803,7 @@ func rewriteValuePPC64_OpLsh64x32(v *Value) bool {
break
}
v.reset(OpPPC64SLDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -3032,7 +3032,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Lsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SLWconst x [c])
+ // result: (SLWconst x [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -3043,7 +3043,7 @@ func rewriteValuePPC64_OpLsh8x32(v *Value) bool {
break
}
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v.AddArg(x)
return true
}
@@ -10314,12 +10314,16 @@ func rewriteValuePPC64_OpPPC64MTVSRD(v *Value) bool {
b := v.Block
typ := &b.Func.Config.Types
// match: (MTVSRD (MOVDconst [c]))
+ // cond: !math.IsNaN(math.Float64frombits(uint64(c)))
// result: (FMOVDconst [math.Float64frombits(uint64(c))])
for {
if v_0.Op != OpPPC64MOVDconst {
break
}
c := auxIntToInt64(v_0.AuxInt)
+ if !(!math.IsNaN(math.Float64frombits(uint64(c)))) {
+ break
+ }
v.reset(OpPPC64FMOVDconst)
v.AuxInt = float64ToAuxInt(math.Float64frombits(uint64(c)))
return true
@@ -12042,7 +12046,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLD x (MOVDconst [c]))
- // result: (SLDconst [c] x)
+ // result: (SLDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12050,7 +12054,7 @@ func rewriteValuePPC64_OpPPC64SLD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12060,7 +12064,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SLW x (MOVDconst [c]))
- // result: (SLWconst [c] x)
+ // result: (SLWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12068,7 +12072,7 @@ func rewriteValuePPC64_OpPPC64SLW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SLWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12078,7 +12082,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAD x (MOVDconst [c]))
- // result: (SRADconst [c] x)
+ // result: (SRADconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12086,7 +12090,7 @@ func rewriteValuePPC64_OpPPC64SRAD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRADconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12096,7 +12100,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRAW x (MOVDconst [c]))
- // result: (SRAWconst [c] x)
+ // result: (SRAWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12104,7 +12108,7 @@ func rewriteValuePPC64_OpPPC64SRAW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12114,7 +12118,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRD x (MOVDconst [c]))
- // result: (SRDconst [c] x)
+ // result: (SRDconst [c&63 | (c>>6&1*63)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12122,7 +12126,7 @@ func rewriteValuePPC64_OpPPC64SRD(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&63 | (c >> 6 & 1 * 63))
v.AddArg(x)
return true
}
@@ -12132,7 +12136,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
v_1 := v.Args[1]
v_0 := v.Args[0]
// match: (SRW x (MOVDconst [c]))
- // result: (SRWconst [c] x)
+ // result: (SRWconst [c&31 | (c>>5&1*31)] x)
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12140,7 +12144,7 @@ func rewriteValuePPC64_OpPPC64SRW(v *Value) bool {
}
c := auxIntToInt64(v_1.AuxInt)
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c&31 | (c >> 5 & 1 * 31))
v.AddArg(x)
return true
}
@@ -12626,7 +12630,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh16Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SRWconst (ZeroExt16to32 x) [c])
+ // result: (SRWconst (ZeroExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12637,7 +12641,7 @@ func rewriteValuePPC64_OpRsh16Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpZeroExt16to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@@ -12847,7 +12851,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh16x32 x (MOVDconst [c]))
// cond: uint32(c) < 16
- // result: (SRAWconst (SignExt16to32 x) [c])
+ // result: (SRAWconst (SignExt16to32 x) [c&15])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -12858,7 +12862,7 @@ func rewriteValuePPC64_OpRsh16x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 15)
v0 := b.NewValue0(v.Pos, OpSignExt16to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)
@@ -13068,7 +13072,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh32Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SRWconst x [c])
+ // result: (SRWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13079,7 +13083,7 @@ func rewriteValuePPC64_OpRsh32Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -13373,7 +13377,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh32x32 x (MOVDconst [c]))
// cond: uint32(c) < 32
- // result: (SRAWconst x [c])
+ // result: (SRAWconst x [c&31])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13384,7 +13388,7 @@ func rewriteValuePPC64_OpRsh32x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 31)
v.AddArg(x)
return true
}
@@ -13680,7 +13684,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh64Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SRDconst x [c])
+ // result: (SRDconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13691,7 +13695,7 @@ func rewriteValuePPC64_OpRsh64Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRDconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -13985,7 +13989,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh64x32 x (MOVDconst [c]))
// cond: uint32(c) < 64
- // result: (SRADconst x [c])
+ // result: (SRADconst x [c&63])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -13996,7 +14000,7 @@ func rewriteValuePPC64_OpRsh64x32(v *Value) bool {
break
}
v.reset(OpPPC64SRADconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 63)
v.AddArg(x)
return true
}
@@ -14296,7 +14300,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh8Ux32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SRWconst (ZeroExt8to32 x) [c])
+ // result: (SRWconst (ZeroExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -14307,7 +14311,7 @@ func rewriteValuePPC64_OpRsh8Ux32(v *Value) bool {
break
}
v.reset(OpPPC64SRWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpZeroExt8to32, typ.UInt32)
v0.AddArg(x)
v.AddArg(v0)
@@ -14517,7 +14521,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
typ := &b.Func.Config.Types
// match: (Rsh8x32 x (MOVDconst [c]))
// cond: uint32(c) < 8
- // result: (SRAWconst (SignExt8to32 x) [c])
+ // result: (SRAWconst (SignExt8to32 x) [c&7])
for {
x := v_0
if v_1.Op != OpPPC64MOVDconst {
@@ -14528,7 +14532,7 @@ func rewriteValuePPC64_OpRsh8x32(v *Value) bool {
break
}
v.reset(OpPPC64SRAWconst)
- v.AuxInt = int64ToAuxInt(c)
+ v.AuxInt = int64ToAuxInt(c & 7)
v0 := b.NewValue0(v.Pos, OpSignExt8to32, typ.Int32)
v0.AddArg(x)
v.AddArg(v0)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index 6b91c08628..c178290343 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -5120,7 +5120,105 @@ func rewriteValueRISCV64_OpZeroExt8to64(v *Value) bool {
}
func rewriteBlockRISCV64(b *Block) bool {
switch b.Kind {
+ case BlockRISCV64BEQ:
+ // match: (BEQ (MOVDconst [0]) cond yes no)
+ // result: (BEQZ cond yes no)
+ for b.Controls[0].Op == OpRISCV64MOVDconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ cond := b.Controls[1]
+ b.resetWithControl(BlockRISCV64BEQZ, cond)
+ return true
+ }
+ // match: (BEQ cond (MOVDconst [0]) yes no)
+ // result: (BEQZ cond yes no)
+ for b.Controls[1].Op == OpRISCV64MOVDconst {
+ cond := b.Controls[0]
+ v_1 := b.Controls[1]
+ if auxIntToInt64(v_1.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockRISCV64BEQZ, cond)
+ return true
+ }
+ case BlockRISCV64BEQZ:
+ // match: (BEQZ (SEQZ x) yes no)
+ // result: (BNEZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SEQZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BNEZ, x)
+ return true
+ }
+ // match: (BEQZ (SNEZ x) yes no)
+ // result: (BEQZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SNEZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BEQZ, x)
+ return true
+ }
+ // match: (BEQZ (SUB x y) yes no)
+ // result: (BEQ x y yes no)
+ for b.Controls[0].Op == OpRISCV64SUB {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BEQ, x, y)
+ return true
+ }
+ // match: (BEQZ (SLT x y) yes no)
+ // result: (BGE x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLT {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BGE, x, y)
+ return true
+ }
+ // match: (BEQZ (SLTU x y) yes no)
+ // result: (BGEU x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLTU {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BGEU, x, y)
+ return true
+ }
+ case BlockRISCV64BNE:
+ // match: (BNE (MOVDconst [0]) cond yes no)
+ // result: (BNEZ cond yes no)
+ for b.Controls[0].Op == OpRISCV64MOVDconst {
+ v_0 := b.Controls[0]
+ if auxIntToInt64(v_0.AuxInt) != 0 {
+ break
+ }
+ cond := b.Controls[1]
+ b.resetWithControl(BlockRISCV64BNEZ, cond)
+ return true
+ }
+ // match: (BNE cond (MOVDconst [0]) yes no)
+ // result: (BNEZ cond yes no)
+ for b.Controls[1].Op == OpRISCV64MOVDconst {
+ cond := b.Controls[0]
+ v_1 := b.Controls[1]
+ if auxIntToInt64(v_1.AuxInt) != 0 {
+ break
+ }
+ b.resetWithControl(BlockRISCV64BNEZ, cond)
+ return true
+ }
case BlockRISCV64BNEZ:
+ // match: (BNEZ (SEQZ x) yes no)
+ // result: (BEQZ x yes no)
+ for b.Controls[0].Op == OpRISCV64SEQZ {
+ v_0 := b.Controls[0]
+ x := v_0.Args[0]
+ b.resetWithControl(BlockRISCV64BEQZ, x)
+ return true
+ }
// match: (BNEZ (SNEZ x) yes no)
// result: (BNEZ x yes no)
for b.Controls[0].Op == OpRISCV64SNEZ {
@@ -5129,6 +5227,33 @@ func rewriteBlockRISCV64(b *Block) bool {
b.resetWithControl(BlockRISCV64BNEZ, x)
return true
}
+ // match: (BNEZ (SUB x y) yes no)
+ // result: (BNE x y yes no)
+ for b.Controls[0].Op == OpRISCV64SUB {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BNE, x, y)
+ return true
+ }
+ // match: (BNEZ (SLT x y) yes no)
+ // result: (BLT x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLT {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BLT, x, y)
+ return true
+ }
+ // match: (BNEZ (SLTU x y) yes no)
+ // result: (BLTU x y yes no)
+ for b.Controls[0].Op == OpRISCV64SLTU {
+ v_0 := b.Controls[0]
+ y := v_0.Args[1]
+ x := v_0.Args[0]
+ b.resetWithControl2(BlockRISCV64BLTU, x, y)
+ return true
+ }
case BlockIf:
// match: (If cond yes no)
// result: (BNEZ cond yes no)
diff --git a/src/cmd/compile/internal/ssa/rewrite_test.go b/src/cmd/compile/internal/ssa/rewrite_test.go
index 4321c307dc..1a15d8c940 100644
--- a/src/cmd/compile/internal/ssa/rewrite_test.go
+++ b/src/cmd/compile/internal/ssa/rewrite_test.go
@@ -27,3 +27,12 @@ func TestMoveSmall(t *testing.T) {
}
}
}
+
+func TestSubFlags(t *testing.T) {
+ if !subFlags32(0, 1).lt() {
+ t.Errorf("subFlags32(0,1).lt() returned false")
+ }
+ if !subFlags32(0, 1).ult() {
+ t.Errorf("subFlags32(0,1).ult() returned false")
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/tuple.go b/src/cmd/compile/internal/ssa/tuple.go
new file mode 100644
index 0000000000..38deabf83d
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/tuple.go
@@ -0,0 +1,59 @@
+// Copyright 2020 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
+
+// tightenTupleSelectors ensures that tuple selectors (Select0 and
+// Select1 ops) are in the same block as their tuple generator. The
+// function also ensures that there are no duplicate tuple selectors.
+// These properties are expected by the scheduler but may not have
+// been maintained by the optimization pipeline up to this point.
+//
+// See issues 16741 and 39472.
+func tightenTupleSelectors(f *Func) {
+ selectors := make(map[struct {
+ id ID
+ op Op
+ }]*Value)
+ for _, b := range f.Blocks {
+ for _, selector := range b.Values {
+ if selector.Op != OpSelect0 && selector.Op != OpSelect1 {
+ continue
+ }
+
+ // Get the tuple generator to use as a key for de-duplication.
+ tuple := selector.Args[0]
+ if !tuple.Type.IsTuple() {
+ f.Fatalf("arg of tuple selector %s is not a tuple: %s", selector.String(), tuple.LongString())
+ }
+
+ // If there is a pre-existing selector in the target block then
+ // use that. Do this even if the selector is already in the
+ // target block to avoid duplicate tuple selectors.
+ key := struct {
+ id ID
+ op Op
+ }{tuple.ID, selector.Op}
+ if t := selectors[key]; t != nil {
+ if selector != t {
+ selector.copyOf(t)
+ }
+ continue
+ }
+
+ // If the selector is in the wrong block copy it into the target
+ // block.
+ if selector.Block != tuple.Block {
+ t := selector.copyInto(tuple.Block)
+ selector.copyOf(t)
+ selectors[key] = t
+ continue
+ }
+
+ // The selector is in the target block. Add it to the map so it
+ // cannot be duplicated.
+ selectors[key] = selector
+ }
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index ca5b884946..63c8f3decf 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -206,6 +206,8 @@ func (v *Value) auxString() string {
return fmt.Sprintf(" {%s}", v.Aux.(Op))
case auxS390XCCMask, auxS390XRotateParams:
return fmt.Sprintf(" {%v}", v.Aux)
+ case auxFlagConstant:
+ return fmt.Sprintf("[%s]", flagConstant(v.AuxInt))
}
return ""
}
diff --git a/src/cmd/compile/internal/x86/ssa.go b/src/cmd/compile/internal/x86/ssa.go
index 0c7e5bdb97..2de978c28a 100644
--- a/src/cmd/compile/internal/x86/ssa.go
+++ b/src/cmd/compile/internal/x86/ssa.go
@@ -885,11 +885,11 @@ var blockJump = [...]struct {
ssa.Block386NAN: {x86.AJPS, x86.AJPC},
}
-var eqfJumps = [2][2]gc.FloatingEQNEJump{
+var eqfJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPS, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 1}, {Jump: x86.AJPC, Index: 0}}, // next == b.Succs[1]
}
-var nefJumps = [2][2]gc.FloatingEQNEJump{
+var nefJumps = [2][2]gc.IndexJump{
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPC, Index: 1}}, // next == b.Succs[0]
{{Jump: x86.AJNE, Index: 0}, {Jump: x86.AJPS, Index: 0}}, // next == b.Succs[1]
}
@@ -929,10 +929,10 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
p.To.Sym = b.Aux.(*obj.LSym)
case ssa.Block386EQF:
- s.FPJump(b, next, &eqfJumps)
+ s.CombJump(b, next, &eqfJumps)
case ssa.Block386NEF:
- s.FPJump(b, next, &nefJumps)
+ s.CombJump(b, next, &nefJumps)
case ssa.Block386EQ, ssa.Block386NE,
ssa.Block386LT, ssa.Block386GE,
diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go
index d22ee1d361..9e2b4f33b8 100644
--- a/src/cmd/dist/build.go
+++ b/src/cmd/dist/build.go
@@ -31,7 +31,6 @@ var (
goos string
goarm string
go386 string
- goamd64 string
gomips string
gomips64 string
goppc64 string
@@ -152,12 +151,6 @@ func xinit() {
}
go386 = b
- b = os.Getenv("GOAMD64")
- if b == "" {
- b = "alignedjumps"
- }
- goamd64 = b
-
b = os.Getenv("GOMIPS")
if b == "" {
b = "hardfloat"
@@ -230,7 +223,6 @@ func xinit() {
// For tools being invoked but also for os.ExpandEnv.
os.Setenv("GO386", go386)
- os.Setenv("GOAMD64", goamd64)
os.Setenv("GOARCH", goarch)
os.Setenv("GOARM", goarm)
os.Setenv("GOHOSTARCH", gohostarch)
@@ -1171,9 +1163,6 @@ func cmdenv() {
if goarch == "386" {
xprintf(format, "GO386", go386)
}
- if goarch == "amd64" {
- xprintf(format, "GOAMD64", goamd64)
- }
if goarch == "mips" || goarch == "mipsle" {
xprintf(format, "GOMIPS", gomips)
}
diff --git a/src/cmd/dist/buildruntime.go b/src/cmd/dist/buildruntime.go
index f11933c925..2744951597 100644
--- a/src/cmd/dist/buildruntime.go
+++ b/src/cmd/dist/buildruntime.go
@@ -42,7 +42,6 @@ func mkzversion(dir, file string) {
//
// const defaultGOROOT = <goroot>
// const defaultGO386 = <go386>
-// const defaultGOAMD64 = <goamd64>
// const defaultGOARM = <goarm>
// const defaultGOMIPS = <gomips>
// const defaultGOMIPS64 = <gomips64>
@@ -72,7 +71,6 @@ func mkzbootstrap(file string) {
fmt.Fprintf(&buf, "import \"runtime\"\n")
fmt.Fprintln(&buf)
fmt.Fprintf(&buf, "const defaultGO386 = `%s`\n", go386)
- fmt.Fprintf(&buf, "const defaultGOAMD64 = `%s`\n", goamd64)
fmt.Fprintf(&buf, "const defaultGOARM = `%s`\n", goarm)
fmt.Fprintf(&buf, "const defaultGOMIPS = `%s`\n", gomips)
fmt.Fprintf(&buf, "const defaultGOMIPS64 = `%s`\n", gomips64)
diff --git a/src/cmd/dist/buildtool.go b/src/cmd/dist/buildtool.go
index d055f468e9..9502dac4eb 100644
--- a/src/cmd/dist/buildtool.go
+++ b/src/cmd/dist/buildtool.go
@@ -115,6 +115,7 @@ var ignorePrefixes = []string{
// These must not be copied into the bootstrap build directory.
var ignoreSuffixes = []string{
"_arm64.s",
+ "_arm64_test.s",
"_arm64.go",
"_riscv64.s",
"_riscv64.go",
diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go
index 08ef056164..2dc9459215 100644
--- a/src/cmd/dist/test.go
+++ b/src/cmd/dist/test.go
@@ -178,15 +178,6 @@ func (t *tester) run() {
return
}
- // We must unset GOROOT_FINAL before tests, because runtime/debug requires
- // correct access to source code, so if we have GOROOT_FINAL in effect,
- // at least runtime/debug test will fail.
- // If GOROOT_FINAL was set before, then now all the commands will appear stale.
- // Nothing we can do about that other than not checking them below.
- // (We call checkNotStale but only with "std" not "cmd".)
- os.Setenv("GOROOT_FINAL_OLD", os.Getenv("GOROOT_FINAL")) // for cmd/link test
- os.Unsetenv("GOROOT_FINAL")
-
for _, name := range t.runNames {
if !t.isRegisteredTestName(name) {
fatalf("unknown test %q", name)
@@ -470,6 +461,18 @@ func (t *tester) registerTests() {
})
}
+ // Test the ios build tag on darwin/amd64 for the iOS simulator.
+ if goos == "darwin" && !t.iOS() {
+ t.tests = append(t.tests, distTest{
+ name: "amd64ios",
+ heading: "ios tag on darwin/amd64",
+ fn: func(dt *distTest) error {
+ t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=ios", "-run=SystemRoots", "crypto/x509")
+ return nil
+ },
+ })
+ }
+
if t.race {
return
}
diff --git a/src/cmd/fix/egltype.go b/src/cmd/fix/egltype.go
index c8c4f03e97..cb0f7a73de 100644
--- a/src/cmd/fix/egltype.go
+++ b/src/cmd/fix/egltype.go
@@ -9,13 +9,14 @@ import (
)
func init() {
- register(eglFix)
+ register(eglFixDisplay)
+ register(eglFixConfig)
}
-var eglFix = fix{
+var eglFixDisplay = fix{
name: "egl",
date: "2018-12-15",
- f: eglfix,
+ f: eglfixDisp,
desc: `Fixes initializers of EGLDisplay`,
disabled: false,
}
@@ -25,8 +26,27 @@ var eglFix = fix{
// New state:
// type EGLDisplay uintptr
// This fix finds nils initializing these types and replaces the nils with 0s.
-func eglfix(f *ast.File) bool {
+func eglfixDisp(f *ast.File) bool {
return typefix(f, func(s string) bool {
return s == "C.EGLDisplay"
})
}
+
+var eglFixConfig = fix{
+ name: "eglconf",
+ date: "2020-05-30",
+ f: eglfixConfig,
+ desc: `Fixes initializers of EGLConfig`,
+ disabled: false,
+}
+
+// Old state:
+// type EGLConfig unsafe.Pointer
+// New state:
+// type EGLConfig uintptr
+// This fix finds nils initializing these types and replaces the nils with 0s.
+func eglfixConfig(f *ast.File) bool {
+ return typefix(f, func(s string) bool {
+ return s == "C.EGLConfig"
+ })
+}
diff --git a/src/cmd/fix/egltype_test.go b/src/cmd/fix/egltype_test.go
index 35ffe92595..9b64a7c20b 100644
--- a/src/cmd/fix/egltype_test.go
+++ b/src/cmd/fix/egltype_test.go
@@ -4,182 +4,193 @@
package main
+import "strings"
+
func init() {
- addTestCases(eglTests, eglfix)
+ addTestCases(eglTestsFor("EGLDisplay"), eglfixDisp)
+ addTestCases(eglTestsFor("EGLConfig"), eglfixConfig)
}
-var eglTests = []testCase{
- {
- Name: "egl.localVariable",
- In: `package main
+func eglTestsFor(tname string) []testCase {
+ var eglTests = []testCase{
+ {
+ Name: "egl.localVariable",
+ In: `package main
import "C"
func f() {
- var x C.EGLDisplay = nil
+ var x C.$EGLTYPE = nil
x = nil
x, x = nil, nil
}
`,
- Out: `package main
+ Out: `package main
import "C"
func f() {
- var x C.EGLDisplay = 0
+ var x C.$EGLTYPE = 0
x = 0
x, x = 0, 0
}
`,
- },
- {
- Name: "egl.globalVariable",
- In: `package main
+ },
+ {
+ Name: "egl.globalVariable",
+ In: `package main
import "C"
-var x C.EGLDisplay = nil
+var x C.$EGLTYPE = nil
func f() {
x = nil
}
`,
- Out: `package main
+ Out: `package main
import "C"
-var x C.EGLDisplay = 0
+var x C.$EGLTYPE = 0
func f() {
x = 0
}
`,
- },
- {
- Name: "egl.EqualArgument",
- In: `package main
+ },
+ {
+ Name: "egl.EqualArgument",
+ In: `package main
import "C"
-var x C.EGLDisplay
+var x C.$EGLTYPE
var y = x == nil
var z = x != nil
`,
- Out: `package main
+ Out: `package main
import "C"
-var x C.EGLDisplay
+var x C.$EGLTYPE
var y = x == 0
var z = x != 0
`,
- },
- {
- Name: "egl.StructField",
- In: `package main
+ },
+ {
+ Name: "egl.StructField",
+ In: `package main
import "C"
type T struct {
- x C.EGLDisplay
+ x C.$EGLTYPE
}
var t = T{x: nil}
`,
- Out: `package main
+ Out: `package main
import "C"
type T struct {
- x C.EGLDisplay
+ x C.$EGLTYPE
}
var t = T{x: 0}
`,
- },
- {
- Name: "egl.FunctionArgument",
- In: `package main
+ },
+ {
+ Name: "egl.FunctionArgument",
+ In: `package main
import "C"
-func f(x C.EGLDisplay) {
+func f(x C.$EGLTYPE) {
}
func g() {
f(nil)
}
`,
- Out: `package main
+ Out: `package main
import "C"
-func f(x C.EGLDisplay) {
+func f(x C.$EGLTYPE) {
}
func g() {
f(0)
}
`,
- },
- {
- Name: "egl.ArrayElement",
- In: `package main
+ },
+ {
+ Name: "egl.ArrayElement",
+ In: `package main
import "C"
-var x = [3]C.EGLDisplay{nil, nil, nil}
+var x = [3]C.$EGLTYPE{nil, nil, nil}
`,
- Out: `package main
+ Out: `package main
import "C"
-var x = [3]C.EGLDisplay{0, 0, 0}
+var x = [3]C.$EGLTYPE{0, 0, 0}
`,
- },
- {
- Name: "egl.SliceElement",
- In: `package main
+ },
+ {
+ Name: "egl.SliceElement",
+ In: `package main
import "C"
-var x = []C.EGLDisplay{nil, nil, nil}
+var x = []C.$EGLTYPE{nil, nil, nil}
`,
- Out: `package main
+ Out: `package main
import "C"
-var x = []C.EGLDisplay{0, 0, 0}
+var x = []C.$EGLTYPE{0, 0, 0}
`,
- },
- {
- Name: "egl.MapKey",
- In: `package main
+ },
+ {
+ Name: "egl.MapKey",
+ In: `package main
import "C"
-var x = map[C.EGLDisplay]int{nil: 0}
+var x = map[C.$EGLTYPE]int{nil: 0}
`,
- Out: `package main
+ Out: `package main
import "C"
-var x = map[C.EGLDisplay]int{0: 0}
+var x = map[C.$EGLTYPE]int{0: 0}
`,
- },
- {
- Name: "egl.MapValue",
- In: `package main
+ },
+ {
+ Name: "egl.MapValue",
+ In: `package main
import "C"
-var x = map[int]C.EGLDisplay{0: nil}
+var x = map[int]C.$EGLTYPE{0: nil}
`,
- Out: `package main
+ Out: `package main
import "C"
-var x = map[int]C.EGLDisplay{0: 0}
+var x = map[int]C.$EGLTYPE{0: 0}
`,
- },
+ },
+ }
+ for i := range eglTests {
+ t := &eglTests[i]
+ t.In = strings.ReplaceAll(t.In, "$EGLTYPE", tname)
+ t.Out = strings.ReplaceAll(t.Out, "$EGLTYPE", tname)
+ }
+ return eglTests
}
diff --git a/src/cmd/go.mod b/src/cmd/go.mod
index 1302449b1b..274ef0d9f0 100644
--- a/src/cmd/go.mod
+++ b/src/cmd/go.mod
@@ -5,9 +5,9 @@ go 1.15
require (
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 // indirect
- golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
- golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
- golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
+ golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
+ golang.org/x/mod v0.3.0
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
- golang.org/x/tools v0.0.0-20200504152539-33427f1b0364
+ golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
)
diff --git a/src/cmd/go.sum b/src/cmd/go.sum
index e66011dd86..30a0be03e4 100644
--- a/src/cmd/go.sum
+++ b/src/cmd/go.sum
@@ -7,15 +7,15 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340 h1:S1+yTUaFPXuDZnPDbO+TrDFIjPzQraYH8/CwSlu9Fac=
github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4 h1:cZG+Ns0n5bdEEsURGnDinFswSebRNMqspbLvxrLZoIc=
-golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
+golang.org/x/arch v0.0.0-20200511175325-f7c78586839d h1:YvwchuJby5xEAPdBGmdAVSiVME50C+RJfJJwJJsGEV8=
+golang.org/x/arch v0.0.0-20200511175325-f7c78586839d/go.mod h1:flIaEI6LNU6xOCD5PaJvn9wGP0agmIOqjrtsKGRguv4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
-golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
-golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2 h1:VUsRDZIYpMs3R7PyYeN7BSbDfYjhxaX6HlWvM5iAEqs=
-golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.3.0 h1:RM4zey1++hCTbCVQfnWeKs9/IEsaBLA8vTkd0WVtmH4=
+golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -28,8 +28,8 @@ golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 h1:5B6i6EAiSYyejWfvc5Rc9BbI3
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
-golang.org/x/tools v0.0.0-20200504152539-33427f1b0364 h1:B3dlRmcq+I6Bd22nHKKa7E+r0/6mLEoJQa75WjfILUE=
-golang.org/x/tools v0.0.0-20200504152539-33427f1b0364/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
+golang.org/x/tools v0.0.0-20200616133436-c1934b75d054 h1:HHeAlu5H9b71C+Fx0K+1dGgVFN1DM1/wz4aoGOA5qS8=
+golang.org/x/tools v0.0.0-20200616133436-c1934b75d054/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go
index 81b4687a6a..2316fb9991 100644
--- a/src/cmd/go/alldocs.go
+++ b/src/cmd/go/alldocs.go
@@ -1313,10 +1313,10 @@
// and its test source files to identify significant problems. If go vet
// finds any problems, go test reports those and does not run the test
// binary. Only a high-confidence subset of the default go vet checks are
-// used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
-// 'printf'. You can see the documentation for these and other vet tests
-// via "go doc cmd/vet". To disable the running of go vet, use the
-// -vet=off flag.
+// used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
+// 'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
+// the documentation for these and other vet tests via "go doc cmd/vet".
+// To disable the running of go vet, use the -vet=off flag.
//
// All test output and summary lines are printed to the go command's
// standard output, even if the test printed them to its own standard
@@ -1480,56 +1480,91 @@
//
// Build constraints
//
-// Build constraints describe the conditions under which each source file
-// should be included in the corresponding package. Build constraints
-// for a given source file may be added by build constraint comments
-// within the file, or by specific patterns in the file's name.
-//
-// A build constraint comment appears before the file's package clause and
-// must be separated from the package clause by at least one blank line.
-// The comment begins with:
+// A build constraint, also known as a build tag, is a line comment that begins
//
// // +build
//
-// and follows with a space-separated list of options on the same line.
-// The constraint is evaluated as the OR of the options.
+// that lists the conditions under which a file should be included in the package.
+// Constraints may appear in any kind of source file (not just Go), but
+// they must appear near the top of the file, preceded
+// only by blank lines and other line comments. These rules mean that in Go
+// files a build constraint must appear before the package clause.
+//
+// To distinguish build constraints from package documentation, a series of
+// build constraints must be followed by a blank line.
+//
+// A build constraint is evaluated as the OR of space-separated options.
// Each option evaluates as the AND of its comma-separated terms.
// Each term consists of letters, digits, underscores, and dots.
-// Each term may be negated with a leading exclamation point.
-//
+// A term may be negated with a preceding !.
// For example, the build constraint:
//
-// // +build linux,386 darwin,!cgo arm
+// // +build linux,386 darwin,!cgo
+//
+// corresponds to the boolean formula:
+//
+// (linux AND 386) OR (darwin AND (NOT cgo))
+//
+// A file may have multiple build constraints. The overall constraint is the AND
+// of the individual constraints. That is, the build constraints:
+//
+// // +build linux darwin
+// // +build amd64
//
-// corresponds to boolean formula:
+// corresponds to the boolean formula:
//
-// (linux AND 386) OR (darwin AND NOT cgo) OR arm
+// (linux OR darwin) AND amd64
//
-// During a particular build, the following terms are satisfied:
-// - the target operating system and architecture, as spelled by
-// runtime.GOOS and runtime.GOARCH respectively
-// - the compiler being used, either "gc" or "gccgo"
-// - "cgo", if the cgo command is supported
-// (see CGO_ENABLED in 'go help environment')
-// - a term for each Go major release, through the current version:
-// "go1.1" from Go version 1.1 onward,
-// "go1.2" from Go version 1.2 onward, and so on
-// - and any additional tags given by the '-tags' flag (see 'go help build').
+// During a particular build, the following words are satisfied:
+//
+// - the target operating system, as spelled by runtime.GOOS, set with the
+// GOOS environment variable.
+// - the target architecture, as spelled by runtime.GOARCH, set with the
+// GOARCH environment variable.
+// - the compiler being used, either "gc" or "gccgo"
+// - "cgo", if the cgo command is supported (see CGO_ENABLED in
+// 'go help environment').
+// - a term for each Go major release, through the current version:
+// "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on.
+// - any additional tags given by the -tags flag (see 'go help build').
+//
+// There are no separate build tags for beta or minor releases.
//
-// An additional build constraint may be derived from the source file name.
// If a file's name, after stripping the extension and a possible _test suffix,
-// matches the patterns *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known
-// GOOS or GOARCH value, then the file is implicitly constrained to that
-// specific GOOS and/or GOARCH, in addition to any other build constraints
-// declared as comments within the file.
+// matches any of the following patterns:
+// *_GOOS
+// *_GOARCH
+// *_GOOS_GOARCH
+// (example: source_windows_amd64.go) where GOOS and GOARCH represent
+// any known operating system and architecture values respectively, then
+// the file is considered to have an implicit build constraint requiring
+// those terms (in addition to any explicit constraints in the file).
+//
+// Using GOOS=android matches build tags and files as for GOOS=linux
+// in addition to android tags and files.
+//
+// Using GOOS=illumos matches build tags and files as for GOOS=solaris
+// in addition to illumos tags and files.
+//
+// To keep a file from being considered for the build:
+//
+// // +build ignore
+//
+// (any other unsatisfied word will work as well, but "ignore" is conventional.)
+//
+// To build a file only when using cgo, and only on Linux and OS X:
//
-// For example, the file:
+// // +build linux,cgo darwin,cgo
//
-// source_windows_amd64.go
+// Such a file is usually paired with another file implementing the
+// default functionality for other systems, which in this case would
+// carry the constraint:
//
-// is implicitly constrained to windows / amd64.
+// // +build !linux,!darwin !cgo
//
-// See 'go doc go/build' for more details.
+// Naming a file dns_windows.go will cause it to be included only when
+// building the package for Windows; similarly, math_386.s will be included
+// only when building the package for 32-bit x86.
//
//
// Build modes
@@ -1754,9 +1789,6 @@
// GO386
// For GOARCH=386, the floating point instruction set.
// Valid values are 387, sse2.
-// GOAMD64
-// For GOARCH=amd64, jumps can be optionally be aligned such that they do not end on
-// or cross 32 byte boundaries. Valid values are alignedjumps (default), normaljumps.
// GOMIPS
// For GOARCH=mips{,le}, whether to use floating point instructions.
// Valid values are hardfloat (default), softfloat.
diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go
index 6b832076b2..31eb1418e5 100644
--- a/src/cmd/go/go_test.go
+++ b/src/cmd/go/go_test.go
@@ -6,7 +6,6 @@ package main_test
import (
"bytes"
- "context"
"debug/elf"
"debug/macho"
"debug/pe"
@@ -114,12 +113,6 @@ var testGo string
var testTmpDir string
var testBin string
-// testCtx is canceled when the test binary is about to time out.
-//
-// If https://golang.org/issue/28135 is accepted, uses of this variable in test
-// functions should be replaced by t.Context().
-var testCtx = context.Background()
-
// The TestMain function creates a go command for testing purposes and
// deletes it after the tests have been run.
func TestMain(m *testing.M) {
@@ -131,23 +124,9 @@ func TestMain(m *testing.M) {
fmt.Printf("SKIP\n")
return
}
- os.Unsetenv("GOROOT_FINAL")
flag.Parse()
- timeoutFlag := flag.Lookup("test.timeout")
- if timeoutFlag != nil {
- // TODO(golang.org/issue/28147): The go command does not pass the
- // test.timeout flag unless either -timeout or -test.timeout is explicitly
- // set on the command line.
- if d := timeoutFlag.Value.(flag.Getter).Get().(time.Duration); d != 0 {
- aBitShorter := d * 95 / 100
- var cancel context.CancelFunc
- testCtx, cancel = context.WithTimeout(testCtx, aBitShorter)
- defer cancel()
- }
- }
-
if *proxyAddr != "" {
StartProxy()
select {}
@@ -200,6 +179,11 @@ func TestMain(m *testing.M) {
}
testGOROOT = goEnv("GOROOT")
os.Setenv("TESTGO_GOROOT", testGOROOT)
+ // Ensure that GOROOT is set explicitly.
+ // Otherwise, if the toolchain was built with GOROOT_FINAL set but has not
+ // yet been moved to its final location, programs that invoke runtime.GOROOT
+ // may accidentally use the wrong path.
+ os.Setenv("GOROOT", testGOROOT)
// The whole GOROOT/pkg tree was installed using the GOHOSTOS/GOHOSTARCH
// toolchain (installed in GOROOT/pkg/tool/GOHOSTOS_GOHOSTARCH).
@@ -236,8 +220,10 @@ func TestMain(m *testing.M) {
}
testCC = strings.TrimSpace(string(out))
- if out, err := exec.Command(testGo, "env", "CGO_ENABLED").Output(); err != nil {
- fmt.Fprintf(os.Stderr, "running testgo failed: %v\n", err)
+ cmd := exec.Command(testGo, "env", "CGO_ENABLED")
+ cmd.Stderr = new(strings.Builder)
+ if out, err := cmd.Output(); err != nil {
+ fmt.Fprintf(os.Stderr, "running testgo failed: %v\n%s", err, cmd.Stderr)
canRun = false
} else {
canCgo, err = strconv.ParseBool(strings.TrimSpace(string(out)))
@@ -829,10 +815,9 @@ func removeAll(dir string) error {
// module cache has 0444 directories;
// make them writable in order to remove content.
filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return nil // ignore errors walking in file system
- }
- if info.IsDir() {
+ // chmod not only directories, but also things that we couldn't even stat
+ // due to permission errors: they may also be unreadable directories.
+ if err != nil || info.IsDir() {
os.Chmod(path, 0777)
}
return nil
diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go
index 21f55e852f..7f8f8e92be 100644
--- a/src/cmd/go/internal/cfg/cfg.go
+++ b/src/cmd/go/internal/cfg/cfg.go
@@ -241,7 +241,6 @@ var (
// Used in envcmd.MkEnv and build ID computations.
GOARM = envOr("GOARM", fmt.Sprint(objabi.GOARM))
GO386 = envOr("GO386", objabi.GO386)
- GOAMD64 = envOr("GOAMD64", objabi.GOAMD64)
GOMIPS = envOr("GOMIPS", objabi.GOMIPS)
GOMIPS64 = envOr("GOMIPS64", objabi.GOMIPS64)
GOPPC64 = envOr("GOPPC64", fmt.Sprintf("%s%d", "power", objabi.GOPPC64))
@@ -267,8 +266,6 @@ func GetArchEnv() (key, val string) {
return "GOARM", GOARM
case "386":
return "GO386", GO386
- case "amd64":
- return "GOAMD64", GOAMD64
case "mips", "mipsle":
return "GOMIPS", GOMIPS
case "mips64", "mips64le":
diff --git a/src/cmd/go/internal/clean/clean.go b/src/cmd/go/internal/clean/clean.go
index d5028de970..99704cb2b1 100644
--- a/src/cmd/go/internal/clean/clean.go
+++ b/src/cmd/go/internal/clean/clean.go
@@ -137,20 +137,27 @@ func runClean(cmd *base.Command, args []string) {
if cfg.BuildN || cfg.BuildX {
b.Showcmd("", "rm -r %s", strings.Join(subdirs, " "))
}
- for _, d := range subdirs {
- // Only print the first error - there may be many.
- // This also mimics what os.RemoveAll(dir) would do.
- if err := os.RemoveAll(d); err != nil && !printedErrors {
- printedErrors = true
- base.Errorf("go clean -cache: %v", err)
+ if !cfg.BuildN {
+ for _, d := range subdirs {
+ // Only print the first error - there may be many.
+ // This also mimics what os.RemoveAll(dir) would do.
+ if err := os.RemoveAll(d); err != nil && !printedErrors {
+ printedErrors = true
+ base.Errorf("go clean -cache: %v", err)
+ }
}
}
}
logFile := filepath.Join(dir, "log.txt")
- if err := os.RemoveAll(logFile); err != nil && !printedErrors {
- printedErrors = true
- base.Errorf("go clean -cache: %v", err)
+ if cfg.BuildN || cfg.BuildX {
+ b.Showcmd("", "rm -f %s", logFile)
+ }
+ if !cfg.BuildN {
+ if err := os.RemoveAll(logFile); err != nil && !printedErrors {
+ printedErrors = true
+ base.Errorf("go clean -cache: %v", err)
+ }
}
}
}
diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go
index 9583b3f327..b937a6155e 100644
--- a/src/cmd/go/internal/help/helpdoc.go
+++ b/src/cmd/go/internal/help/helpdoc.go
@@ -582,9 +582,6 @@ Architecture-specific environment variables:
GO386
For GOARCH=386, the floating point instruction set.
Valid values are 387, sse2.
- GOAMD64
- For GOARCH=amd64, jumps can be optionally be aligned such that they do not end on
- or cross 32 byte boundaries. Valid values are alignedjumps (default), normaljumps.
GOMIPS
For GOARCH=mips{,le}, whether to use floating point instructions.
Valid values are hardfloat (default), softfloat.
@@ -773,55 +770,90 @@ var HelpBuildConstraint = &base.Command{
UsageLine: "buildconstraint",
Short: "build constraints",
Long: `
-Build constraints describe the conditions under which each source file
-should be included in the corresponding package. Build constraints
-for a given source file may be added by build constraint comments
-within the file, or by specific patterns in the file's name.
-
-A build constraint comment appears before the file's package clause and
-must be separated from the package clause by at least one blank line.
-The comment begins with:
+A build constraint, also known as a build tag, is a line comment that begins
// +build
-and follows with a space-separated list of options on the same line.
-The constraint is evaluated as the OR of the options.
+that lists the conditions under which a file should be included in the package.
+Constraints may appear in any kind of source file (not just Go), but
+they must appear near the top of the file, preceded
+only by blank lines and other line comments. These rules mean that in Go
+files a build constraint must appear before the package clause.
+
+To distinguish build constraints from package documentation, a series of
+build constraints must be followed by a blank line.
+
+A build constraint is evaluated as the OR of space-separated options.
Each option evaluates as the AND of its comma-separated terms.
Each term consists of letters, digits, underscores, and dots.
-Each term may be negated with a leading exclamation point.
-
+A term may be negated with a preceding !.
For example, the build constraint:
- // +build linux,386 darwin,!cgo arm
+ // +build linux,386 darwin,!cgo
+
+corresponds to the boolean formula:
+
+ (linux AND 386) OR (darwin AND (NOT cgo))
+
+A file may have multiple build constraints. The overall constraint is the AND
+of the individual constraints. That is, the build constraints:
+
+ // +build linux darwin
+ // +build amd64
-corresponds to boolean formula:
+corresponds to the boolean formula:
- (linux AND 386) OR (darwin AND NOT cgo) OR arm
+ (linux OR darwin) AND amd64
-During a particular build, the following terms are satisfied:
-- the target operating system and architecture, as spelled by
- runtime.GOOS and runtime.GOARCH respectively
-- the compiler being used, either "gc" or "gccgo"
-- "cgo", if the cgo command is supported
- (see CGO_ENABLED in 'go help environment')
-- a term for each Go major release, through the current version:
- "go1.1" from Go version 1.1 onward,
- "go1.2" from Go version 1.2 onward, and so on
-- and any additional tags given by the '-tags' flag (see 'go help build').
+During a particular build, the following words are satisfied:
+
+ - the target operating system, as spelled by runtime.GOOS, set with the
+ GOOS environment variable.
+ - the target architecture, as spelled by runtime.GOARCH, set with the
+ GOARCH environment variable.
+ - the compiler being used, either "gc" or "gccgo"
+ - "cgo", if the cgo command is supported (see CGO_ENABLED in
+ 'go help environment').
+ - a term for each Go major release, through the current version:
+ "go1.1" from Go version 1.1 onward, "go1.12" from Go 1.12, and so on.
+ - any additional tags given by the -tags flag (see 'go help build').
+
+There are no separate build tags for beta or minor releases.
-An additional build constraint may be derived from the source file name.
If a file's name, after stripping the extension and a possible _test suffix,
-matches the patterns *_GOOS, *_GOARCH, or *_GOOS_GOARCH for any known
-GOOS or GOARCH value, then the file is implicitly constrained to that
-specific GOOS and/or GOARCH, in addition to any other build constraints
-declared as comments within the file.
+matches any of the following patterns:
+ *_GOOS
+ *_GOARCH
+ *_GOOS_GOARCH
+(example: source_windows_amd64.go) where GOOS and GOARCH represent
+any known operating system and architecture values respectively, then
+the file is considered to have an implicit build constraint requiring
+those terms (in addition to any explicit constraints in the file).
+
+Using GOOS=android matches build tags and files as for GOOS=linux
+in addition to android tags and files.
+
+Using GOOS=illumos matches build tags and files as for GOOS=solaris
+in addition to illumos tags and files.
+
+To keep a file from being considered for the build:
+
+ // +build ignore
+
+(any other unsatisfied word will work as well, but "ignore" is conventional.)
+
+To build a file only when using cgo, and only on Linux and OS X:
-For example, the file:
+ // +build linux,cgo darwin,cgo
- source_windows_amd64.go
+Such a file is usually paired with another file implementing the
+default functionality for other systems, which in this case would
+carry the constraint:
-is implicitly constrained to windows / amd64.
+ // +build !linux,!darwin !cgo
-See 'go doc go/build' for more details.
+Naming a file dns_windows.go will cause it to be included only when
+building the package for Windows; similarly, math_386.s will be included
+only when building the package for 32-bit x86.
`,
}
diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go
index 61818380c7..e0bd71b40d 100644
--- a/src/cmd/go/internal/load/pkg.go
+++ b/src/cmd/go/internal/load/pkg.go
@@ -217,13 +217,9 @@ func (e *NoGoError) Error() string {
// setLoadPackageDataError returns true if it's safe to load information about
// imported packages, for example, if there was a parse error loading imports
// in one file, but other files are okay.
-func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack) {
- // Include the path on the import stack unless the error includes it already.
- errHasPath := false
- if impErr, ok := err.(ImportPathError); ok && impErr.ImportPath() == path {
- errHasPath = true
- } else if matchErr, ok := err.(*search.MatchError); ok && matchErr.Match.Pattern() == path {
- errHasPath = true
+func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportStack, importPos []token.Position) {
+ matchErr, isMatchErr := err.(*search.MatchError)
+ if isMatchErr && matchErr.Match.Pattern() == path {
if matchErr.Match.IsLiteral() {
// The error has a pattern has a pattern similar to the import path.
// It may be slightly different (./foo matching example.com/foo),
@@ -232,14 +228,6 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
err = matchErr.Err
}
}
- var errStk []string
- if errHasPath {
- errStk = stk.Copy()
- } else {
- stk.Push(path)
- errStk = stk.Copy()
- stk.Pop()
- }
// Replace (possibly wrapped) *build.NoGoError with *load.NoGoError.
// The latter is more specific about the cause.
@@ -251,6 +239,26 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
err = &NoGoError{Package: p}
}
+ // Report the error on the importing package if the problem is with the import declaration
+ // for example, if the package doesn't exist or if the import path is malformed.
+ // On the other hand, don't include a position if the problem is with the imported package,
+ // for example there are no Go files (NoGoError), or there's a problem in the imported
+ // package's source files themselves.
+ //
+ // TODO(matloob): Perhaps make each of those the errors in the first group
+ // (including modload.ImportMissingError, and the corresponding
+ // "cannot find package %q in any of" GOPATH-mode error
+ // produced in build.(*Context).Import; modload.AmbiguousImportError,
+ // and modload.PackageNotInModuleError; and the malformed module path errors
+ // produced in golang.org/x/mod/module.CheckMod) implement an interface
+ // to make it easier to check for them? That would save us from having to
+ // move the modload errors into this package to avoid a package import cycle,
+ // and from having to export an error type for the errors produced in build.
+ if !isMatchErr && nogoErr != nil {
+ stk.Push(path)
+ defer stk.Pop()
+ }
+
// Take only the first error from a scanner.ErrorList. PackageError only
// has room for one position, so we report the first error with a position
// instead of all of the errors without a position.
@@ -263,10 +271,14 @@ func (p *Package) setLoadPackageDataError(err error, path string, stk *ImportSta
}
p.Error = &PackageError{
- ImportStack: errStk,
+ ImportStack: stk.Copy(),
Pos: pos,
Err: err,
}
+
+ if path != stk.Top() {
+ p = setErrorPos(p, importPos)
+ }
}
// Resolve returns the resolved version of imports,
@@ -469,6 +481,13 @@ func (s *ImportStack) Copy() []string {
return append([]string{}, *s...)
}
+func (s *ImportStack) Top() string {
+ if len(*s) == 0 {
+ return ""
+ }
+ return (*s)[len(*s)-1]
+}
+
// shorterThan reports whether sp is shorter than t.
// We use this to record the shortest import sequence
// that leads to a particular package.
@@ -639,13 +658,7 @@ func loadImport(pre *preload, path, srcDir string, parent *Package, stk *ImportS
// Load package.
// loadPackageData may return bp != nil even if an error occurs,
// in order to return partial information.
- p.load(path, stk, bp, err)
- // Add position information unless this is a NoGoError or an ImportCycle error.
- // Import cycles deserve special treatment.
- var g *build.NoGoError
- if p.Error != nil && p.Error.Pos == "" && !errors.As(err, &g) && !p.Error.IsImportCycle {
- p = setErrorPos(p, importPos)
- }
+ p.load(path, stk, importPos, bp, err)
if !cfg.ModulesEnabled && path != cleanImport(path) {
p.Error = &PackageError{
@@ -1579,7 +1592,7 @@ func (p *Package) DefaultExecName() string {
// load populates p using information from bp, err, which should
// be the result of calling build.Context.Import.
// stk contains the import stack, not including path itself.
-func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err error) {
+func (p *Package) load(path string, stk *ImportStack, importPos []token.Position, bp *build.Package, err error) {
p.copyBuild(bp)
// The localPrefix is the path we interpret ./ imports relative to.
@@ -1597,12 +1610,22 @@ func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err err
ImportStack: stk.Copy(),
Err: err,
}
+
+ // Add the importer's position information if the import position exists, and
+ // the current package being examined is the importer.
+ // If we have not yet accepted package p onto the import stack,
+ // then the cause of the error is not within p itself: the error
+ // must be either in an explicit command-line argument,
+ // or on the importer side (indicated by a non-empty importPos).
+ if path != stk.Top() && len(importPos) > 0 {
+ p = setErrorPos(p, importPos)
+ }
}
}
if err != nil {
p.Incomplete = true
- p.setLoadPackageDataError(err, path, stk)
+ p.setLoadPackageDataError(err, path, stk, importPos)
}
useBindir := p.Name == "main"
@@ -1616,6 +1639,8 @@ func (p *Package) load(path string, stk *ImportStack, bp *build.Package, err err
if useBindir {
// Report an error when the old code.google.com/p/go.tools paths are used.
if InstallTargetDir(p) == StalePath {
+ // TODO(matloob): remove this branch, and StalePath itself. code.google.com/p/go is so
+ // old, even this code checking for it is stale now!
newPath := strings.Replace(p.ImportPath, "code.google.com/p/go.", "golang.org/x/", 1)
e := ImportErrorf(p.ImportPath, "the %v command has moved; use %v instead.", p.ImportPath, newPath)
setError(e)
@@ -2169,8 +2194,10 @@ func PackagesAndErrors(patterns []string) []*Package {
// Report it as a synthetic package.
p := new(Package)
p.ImportPath = m.Pattern()
- var stk ImportStack // empty stack, since the error arose from a pattern, not an import
- p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk)
+ // Pass an empty ImportStack and nil importPos: the error arose from a pattern, not an import.
+ var stk ImportStack
+ var importPos []token.Position
+ p.setLoadPackageDataError(m.Errs[0], m.Pattern(), &stk, importPos)
p.Incomplete = true
p.Match = append(p.Match, m.Pattern())
p.Internal.CmdlinePkg = true
@@ -2316,7 +2343,7 @@ func GoFilesPackage(gofiles []string) *Package {
pkg := new(Package)
pkg.Internal.Local = true
pkg.Internal.CmdlineFiles = true
- pkg.load("command-line-arguments", &stk, bp, err)
+ pkg.load("command-line-arguments", &stk, nil, bp, err)
pkg.Internal.LocalPrefix = dirToImportPath(dir)
pkg.ImportPath = "command-line-arguments"
pkg.Target = ""
diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go
index 51b644c4df..6d251e8358 100644
--- a/src/cmd/go/internal/load/test.go
+++ b/src/cmd/go/internal/load/test.go
@@ -270,7 +270,7 @@ func TestPackagesAndErrors(p *Package, cover *TestCover) (pmain, ptest, pxtest *
// afterward that gathers t.Cover information.
t, err := loadTestFuncs(ptest)
if err != nil && pmain.Error == nil {
- pmain.setLoadPackageDataError(err, p.ImportPath, &stk)
+ pmain.setLoadPackageDataError(err, p.ImportPath, &stk, nil)
}
t.Cover = cover
if len(ptest.GoFiles)+len(ptest.CgoFiles) > 0 {
diff --git a/src/cmd/go/internal/modfetch/proxy.go b/src/cmd/go/internal/modfetch/proxy.go
index 0ca43d4c4a..1c35d0b99b 100644
--- a/src/cmd/go/internal/modfetch/proxy.go
+++ b/src/cmd/go/internal/modfetch/proxy.go
@@ -171,6 +171,14 @@ func proxyList() ([]proxySpec, error) {
fallBackOnError: fallBackOnError,
})
}
+
+ if len(proxyOnce.list) == 0 ||
+ len(proxyOnce.list) == 1 && proxyOnce.list[0].url == "noproxy" {
+ // There were no proxies, other than the implicit "noproxy" added when
+ // GONOPROXY is set. This can happen if GOPROXY is a non-empty string
+ // like "," or " ".
+ proxyOnce.err = fmt.Errorf("GOPROXY list is not the empty string, but contains no entries")
+ }
})
return proxyOnce.list, proxyOnce.err
@@ -191,13 +199,17 @@ func TryProxies(f func(proxy string) error) error {
return err
}
if len(proxies) == 0 {
- return f("off")
+ panic("GOPROXY list is empty")
}
// We try to report the most helpful error to the user. "direct" and "noproxy"
// errors are best, followed by proxy errors other than ErrNotExist, followed
- // by ErrNotExist. Note that errProxyOff, errNoproxy, and errUseProxy are
- // equivalent to ErrNotExist.
+ // by ErrNotExist.
+ //
+ // Note that errProxyOff, errNoproxy, and errUseProxy are equivalent to
+ // ErrNotExist. errUseProxy should only be returned if "noproxy" is the only
+ // proxy. errNoproxy should never be returned, since there should always be a
+ // more useful error from "noproxy" first.
const (
notExistRank = iota
proxyRank
@@ -212,7 +224,7 @@ func TryProxies(f func(proxy string) error) error {
}
isNotExistErr := errors.Is(err, os.ErrNotExist)
- if proxy.url == "direct" || proxy.url == "noproxy" {
+ if proxy.url == "direct" || (proxy.url == "noproxy" && err != errUseProxy) {
bestErr = err
bestErrRank = directRank
} else if bestErrRank <= proxyRank && !isNotExistErr {
diff --git a/src/cmd/go/internal/modget/get.go b/src/cmd/go/internal/modget/get.go
index 8d740471b0..4c6982426f 100644
--- a/src/cmd/go/internal/modget/get.go
+++ b/src/cmd/go/internal/modget/get.go
@@ -350,11 +350,15 @@ func runGet(cmd *base.Command, args []string) {
// package in the main module. If the path contains wildcards but
// matches no packages, we'll warn after package loading.
if !strings.Contains(path, "...") {
- var pkgs []string
+ m := search.NewMatch(path)
if pkgPath := modload.DirImportPath(path); pkgPath != "." {
- pkgs = modload.TargetPackages(pkgPath)
+ m = modload.TargetPackages(pkgPath)
}
- if len(pkgs) == 0 {
+ if len(m.Pkgs) == 0 {
+ for _, err := range m.Errs {
+ base.Errorf("go get %s: %v", arg, err)
+ }
+
abs, err := filepath.Abs(path)
if err != nil {
abs = path
@@ -394,7 +398,7 @@ func runGet(cmd *base.Command, args []string) {
default:
// The argument is a package or module path.
if modload.HasModRoot() {
- if pkgs := modload.TargetPackages(path); len(pkgs) != 0 {
+ if m := modload.TargetPackages(path); len(m.Pkgs) != 0 {
// The path is in the main module. Nothing to query.
if vers != "upgrade" && vers != "patch" {
base.Errorf("go get %s: can't request explicit version of path in main module", arg)
diff --git a/src/cmd/go/internal/modload/import.go b/src/cmd/go/internal/modload/import.go
index 162c29d2a6..4d2bc805e2 100644
--- a/src/cmd/go/internal/modload/import.go
+++ b/src/cmd/go/internal/modload/import.go
@@ -126,7 +126,9 @@ func Import(path string) (m module.Version, dir string, err error) {
pathIsStd := search.IsStandardImportPath(path)
if pathIsStd && goroot.IsStandardPackage(cfg.GOROOT, cfg.BuildContext.Compiler, path) {
if targetInGorootSrc {
- if dir, ok := dirInModule(path, targetPrefix, ModRoot(), true); ok {
+ if dir, ok, err := dirInModule(path, targetPrefix, ModRoot(), true); err != nil {
+ return module.Version{}, dir, err
+ } else if ok {
return Target, dir, nil
}
}
@@ -137,8 +139,8 @@ func Import(path string) (m module.Version, dir string, err error) {
// -mod=vendor is special.
// Everything must be in the main module or the main module's vendor directory.
if cfg.BuildMod == "vendor" {
- mainDir, mainOK := dirInModule(path, targetPrefix, ModRoot(), true)
- vendorDir, vendorOK := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
+ mainDir, mainOK, mainErr := dirInModule(path, targetPrefix, ModRoot(), true)
+ vendorDir, vendorOK, _ := dirInModule(path, "", filepath.Join(ModRoot(), "vendor"), false)
if mainOK && vendorOK {
return module.Version{}, "", &AmbiguousImportError{importPath: path, Dirs: []string{mainDir, vendorDir}}
}
@@ -148,6 +150,9 @@ func Import(path string) (m module.Version, dir string, err error) {
if !vendorOK && mainDir != "" {
return Target, mainDir, nil
}
+ if mainErr != nil {
+ return module.Version{}, "", mainErr
+ }
readVendorList()
return vendorPkgModule[path], vendorDir, nil
}
@@ -170,8 +175,9 @@ func Import(path string) (m module.Version, dir string, err error) {
// not ambiguous.
return module.Version{}, "", err
}
- dir, ok := dirInModule(path, m.Path, root, isLocal)
- if ok {
+ if dir, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
+ return module.Version{}, "", err
+ } else if ok {
mods = append(mods, m)
dirs = append(dirs, dir)
}
@@ -247,8 +253,9 @@ func Import(path string) (m module.Version, dir string, err error) {
// Report fetch error as above.
return module.Version{}, "", err
}
- _, ok := dirInModule(path, m.Path, root, isLocal)
- if ok {
+ if _, ok, err := dirInModule(path, m.Path, root, isLocal); err != nil {
+ return m, "", err
+ } else if ok {
return m, "", &ImportMissingError{Path: path, Module: m}
}
}
@@ -319,19 +326,29 @@ func maybeInModule(path, mpath string) bool {
len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath
}
-var haveGoModCache, haveGoFilesCache par.Cache
+var (
+ haveGoModCache par.Cache // dir → bool
+ haveGoFilesCache par.Cache // dir → goFilesEntry
+)
+
+type goFilesEntry struct {
+ haveGoFiles bool
+ err error
+}
// dirInModule locates the directory that would hold the package named by the given path,
// if it were in the module with module path mpath and root mdir.
// If path is syntactically not within mpath,
// or if mdir is a local file tree (isLocal == true) and the directory
// that would hold path is in a sub-module (covered by a go.mod below mdir),
-// dirInModule returns "", false.
+// dirInModule returns "", false, nil.
//
// Otherwise, dirInModule returns the name of the directory where
// Go source files would be expected, along with a boolean indicating
// whether there are in fact Go source files in that directory.
-func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool) {
+// A non-nil error indicates that the existence of the directory and/or
+// source files could not be determined, for example due to a permission error.
+func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFiles bool, err error) {
// Determine where to expect the package.
if path == mpath {
dir = mdir
@@ -340,7 +357,7 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
} else if len(path) > len(mpath) && path[len(mpath)] == '/' && path[:len(mpath)] == mpath {
dir = filepath.Join(mdir, path[len(mpath)+1:])
} else {
- return "", false
+ return "", false, nil
}
// Check that there aren't other modules in the way.
@@ -357,7 +374,7 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
}).(bool)
if haveGoMod {
- return "", false
+ return "", false, nil
}
parent := filepath.Dir(d)
if parent == d {
@@ -374,23 +391,58 @@ func dirInModule(path, mpath, mdir string, isLocal bool) (dir string, haveGoFile
// Are there Go source files in the directory?
// We don't care about build tags, not even "+build ignore".
// We're just looking for a plausible directory.
- haveGoFiles = haveGoFilesCache.Do(dir, func() interface{} {
- f, err := os.Open(dir)
- if err != nil {
- return false
+ res := haveGoFilesCache.Do(dir, func() interface{} {
+ ok, err := isDirWithGoFiles(dir)
+ return goFilesEntry{haveGoFiles: ok, err: err}
+ }).(goFilesEntry)
+
+ return dir, res.haveGoFiles, res.err
+}
+
+func isDirWithGoFiles(dir string) (bool, error) {
+ f, err := os.Open(dir)
+ if err != nil {
+ if os.IsNotExist(err) {
+ return false, nil
}
- defer f.Close()
- names, _ := f.Readdirnames(-1)
- for _, name := range names {
- if strings.HasSuffix(name, ".go") {
- info, err := os.Stat(filepath.Join(dir, name))
- if err == nil && info.Mode().IsRegular() {
- return true
+ return false, err
+ }
+ defer f.Close()
+
+ names, firstErr := f.Readdirnames(-1)
+ if firstErr != nil {
+ if fi, err := f.Stat(); err == nil && !fi.IsDir() {
+ return false, nil
+ }
+
+ // Rewrite the error from ReadDirNames to include the path if not present.
+ // See https://golang.org/issue/38923.
+ var pe *os.PathError
+ if !errors.As(firstErr, &pe) {
+ firstErr = &os.PathError{Op: "readdir", Path: dir, Err: firstErr}
+ }
+ }
+
+ for _, name := range names {
+ if strings.HasSuffix(name, ".go") {
+ info, err := os.Stat(filepath.Join(dir, name))
+ if err == nil && info.Mode().IsRegular() {
+ // If any .go source file exists, the package exists regardless of
+ // errors for other source files. Leave further error reporting for
+ // later.
+ return true, nil
+ }
+ if firstErr == nil {
+ if os.IsNotExist(err) {
+ // If the file was concurrently deleted, or was a broken symlink,
+ // convert the error to an opaque error instead of one matching
+ // os.IsNotExist.
+ err = errors.New(err.Error())
}
+ firstErr = err
}
}
- return false
- }).(bool)
+ }
- return dir, haveGoFiles
+ return false, firstErr
}
diff --git a/src/cmd/go/internal/modload/load.go b/src/cmd/go/internal/modload/load.go
index 21601cb13e..30992e0cc2 100644
--- a/src/cmd/go/internal/modload/load.go
+++ b/src/cmd/go/internal/modload/load.go
@@ -6,6 +6,14 @@ package modload
import (
"bytes"
+ "cmd/go/internal/base"
+ "cmd/go/internal/cfg"
+ "cmd/go/internal/imports"
+ "cmd/go/internal/modfetch"
+ "cmd/go/internal/mvs"
+ "cmd/go/internal/par"
+ "cmd/go/internal/search"
+ "cmd/go/internal/str"
"errors"
"fmt"
"go/build"
@@ -16,15 +24,6 @@ import (
"sort"
"strings"
- "cmd/go/internal/base"
- "cmd/go/internal/cfg"
- "cmd/go/internal/imports"
- "cmd/go/internal/modfetch"
- "cmd/go/internal/mvs"
- "cmd/go/internal/par"
- "cmd/go/internal/search"
- "cmd/go/internal/str"
-
"golang.org/x/mod/module"
)
@@ -100,14 +99,16 @@ func ImportPathsQuiet(patterns []string, tags map[string]bool) []*search.Match {
m.Pkgs = []string{m.Pattern()}
case strings.Contains(m.Pattern(), "..."):
- m.Pkgs = matchPackages(m.Pattern(), loaded.tags, true, buildList)
+ m.Errs = m.Errs[:0]
+ matchPackages(m, loaded.tags, includeStd, buildList)
case m.Pattern() == "all":
loaded.testAll = true
if iterating {
// Enumerate the packages in the main module.
// We'll load the dependencies as we find them.
- m.Pkgs = matchPackages("...", loaded.tags, false, []module.Version{Target})
+ m.Errs = m.Errs[:0]
+ matchPackages(m, loaded.tags, omitStd, []module.Version{Target})
} else {
// Starting with the packages in the main module,
// enumerate the full list of "all".
@@ -274,7 +275,9 @@ func resolveLocalPackage(dir string) (string, error) {
}
pkg := targetPrefix + suffix
- if _, ok := dirInModule(pkg, targetPrefix, modRoot, true); !ok {
+ if _, ok, err := dirInModule(pkg, targetPrefix, modRoot, true); err != nil {
+ return "", err
+ } else if !ok {
return "", &PackageNotInModuleError{Mod: Target, Pattern: pkg}
}
return pkg, nil
@@ -423,7 +426,7 @@ func loadAll(testAll bool) []string {
loaded.testRoots = true
}
all := TargetPackages("...")
- loaded.load(func() []string { return all })
+ loaded.load(func() []string { return all.Pkgs })
checkMultiplePaths()
WriteGoMod()
@@ -435,6 +438,9 @@ func loadAll(testAll bool) []string {
}
paths = append(paths, pkg.path)
}
+ for _, err := range all.Errs {
+ base.Errorf("%v", err)
+ }
base.ExitIfErrors()
return paths
}
@@ -442,12 +448,14 @@ func loadAll(testAll bool) []string {
// TargetPackages returns the list of packages in the target (top-level) module
// matching pattern, which may be relative to the working directory, under all
// build tag settings.
-func TargetPackages(pattern string) []string {
+func TargetPackages(pattern string) *search.Match {
// TargetPackages is relative to the main module, so ensure that the main
// module is a thing that can contain packages.
ModRoot()
- return matchPackages(pattern, imports.AnyTags(), false, []module.Version{Target})
+ m := search.NewMatch(pattern)
+ matchPackages(m, imports.AnyTags(), omitStd, []module.Version{Target})
+ return m
}
// BuildList returns the module build list,
diff --git a/src/cmd/go/internal/modload/mvs.go b/src/cmd/go/internal/modload/mvs.go
index a4bdf3ee00..5dd009d31d 100644
--- a/src/cmd/go/internal/modload/mvs.go
+++ b/src/cmd/go/internal/modload/mvs.go
@@ -157,6 +157,12 @@ func (r *mvsReqs) required(mod module.Version) ([]module.Version, error) {
return r.modFileToList(f), nil
}
+// Max returns the maximum of v1 and v2 according to semver.Compare.
+//
+// As a special case, the version "" is considered higher than all other
+// versions. The main module (also known as the target) has no version and must
+// be chosen over other versions of the same module in the module dependency
+// graph.
func (*mvsReqs) Max(v1, v2 string) string {
if v1 != "" && semver.Compare(v1, v2) == -1 {
return v2
diff --git a/src/cmd/go/internal/modload/query.go b/src/cmd/go/internal/modload/query.go
index 5e9cfdcfe3..acc886bf21 100644
--- a/src/cmd/go/internal/modload/query.go
+++ b/src/cmd/go/internal/modload/query.go
@@ -403,30 +403,42 @@ func QueryPackage(path, query string, allowed func(module.Version) bool) ([]Quer
// possible modules.
func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]QueryResult, error) {
base := pattern
- var match func(m module.Version, root string, isLocal bool) (pkgs []string)
+
+ firstError := func(m *search.Match) error {
+ if len(m.Errs) == 0 {
+ return nil
+ }
+ return m.Errs[0]
+ }
+
+ var match func(mod module.Version, root string, isLocal bool) *search.Match
if i := strings.Index(pattern, "..."); i >= 0 {
base = pathpkg.Dir(pattern[:i+3])
- match = func(m module.Version, root string, isLocal bool) []string {
- return matchPackages(pattern, imports.AnyTags(), false, []module.Version{m})
+ match = func(mod module.Version, root string, isLocal bool) *search.Match {
+ m := search.NewMatch(pattern)
+ matchPackages(m, imports.AnyTags(), omitStd, []module.Version{mod})
+ return m
}
} else {
- match = func(m module.Version, root string, isLocal bool) []string {
- prefix := m.Path
- if m == Target {
+ match = func(mod module.Version, root string, isLocal bool) *search.Match {
+ m := search.NewMatch(pattern)
+ prefix := mod.Path
+ if mod == Target {
prefix = targetPrefix
}
- if _, ok := dirInModule(pattern, prefix, root, isLocal); ok {
- return []string{pattern}
- } else {
- return nil
+ if _, ok, err := dirInModule(pattern, prefix, root, isLocal); err != nil {
+ m.AddError(err)
+ } else if ok {
+ m.Pkgs = []string{pattern}
}
+ return m
}
}
if HasModRoot() {
- pkgs := match(Target, modRoot, true)
- if len(pkgs) > 0 {
+ m := match(Target, modRoot, true)
+ if len(m.Pkgs) > 0 {
if query != "latest" {
return nil, fmt.Errorf("can't query specific version for package %s in the main module (%s)", pattern, Target.Path)
}
@@ -436,9 +448,12 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q
return []QueryResult{{
Mod: Target,
Rev: &modfetch.RevInfo{Version: Target.Version},
- Packages: pkgs,
+ Packages: m.Pkgs,
}}, nil
}
+ if err := firstError(m); err != nil {
+ return nil, err
+ }
}
var (
@@ -466,8 +481,12 @@ func QueryPattern(pattern, query string, allowed func(module.Version) bool) ([]Q
if err != nil {
return r, err
}
- r.Packages = match(r.Mod, root, isLocal)
+ m := match(r.Mod, root, isLocal)
+ r.Packages = m.Pkgs
if len(r.Packages) == 0 {
+ if err := firstError(m); err != nil {
+ return r, err
+ }
return r, &PackageNotInModuleError{
Mod: r.Mod,
Replacement: Replacement(r.Mod),
@@ -684,8 +703,8 @@ func ModuleHasRootPackage(m module.Version) (bool, error) {
if err != nil {
return false, err
}
- _, ok := dirInModule(m.Path, m.Path, root, isLocal)
- return ok, nil
+ _, ok, err := dirInModule(m.Path, m.Path, root, isLocal)
+ return ok, err
}
func versionHasGoMod(m module.Version) (bool, error) {
diff --git a/src/cmd/go/internal/modload/search.go b/src/cmd/go/internal/modload/search.go
index a303f51858..c28e7c0c1e 100644
--- a/src/cmd/go/internal/modload/search.go
+++ b/src/cmd/go/internal/modload/search.go
@@ -10,7 +10,6 @@ import (
"path/filepath"
"strings"
- "cmd/go/internal/base"
"cmd/go/internal/cfg"
"cmd/go/internal/imports"
"cmd/go/internal/search"
@@ -18,14 +17,24 @@ import (
"golang.org/x/mod/module"
)
-// matchPackages returns a list of packages in the list of modules
-// matching the pattern. Package loading assumes the given set of tags.
-func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []module.Version) []string {
- match := func(string) bool { return true }
+type stdFilter int8
+
+const (
+ omitStd = stdFilter(iota)
+ includeStd
+)
+
+// matchPackages is like m.MatchPackages, but uses a local variable (rather than
+// a global) for tags, can include or exclude packages in the standard library,
+// and is restricted to the given list of modules.
+func matchPackages(m *search.Match, tags map[string]bool, filter stdFilter, modules []module.Version) {
+ m.Pkgs = []string{}
+
+ isMatch := func(string) bool { return true }
treeCanMatch := func(string) bool { return true }
- if !search.IsMetaPackage(pattern) {
- match = search.MatchPattern(pattern)
- treeCanMatch = search.TreeCanMatchPattern(pattern)
+ if !m.IsMeta() {
+ isMatch = search.MatchPattern(m.Pattern())
+ treeCanMatch = search.TreeCanMatchPattern(m.Pattern())
}
have := map[string]bool{
@@ -34,7 +43,6 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
if !cfg.BuildContext.CgoEnabled {
have["runtime/cgo"] = true // ignore during walk
}
- var pkgs []string
type pruning int8
const (
@@ -44,8 +52,9 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
walkPkgs := func(root, importPathRoot string, prune pruning) {
root = filepath.Clean(root)
- filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
+ err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
if err != nil {
+ m.AddError(err)
return nil
}
@@ -94,9 +103,9 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
if !have[name] {
have[name] = true
- if match(name) {
+ if isMatch(name) {
if _, _, err := scanDir(path, tags); err != imports.ErrNoGo {
- pkgs = append(pkgs, name)
+ m.Pkgs = append(m.Pkgs, name)
}
}
}
@@ -106,9 +115,12 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
}
return nil
})
+ if err != nil {
+ m.AddError(err)
+ }
}
- if useStd {
+ if filter == includeStd {
walkPkgs(cfg.GOROOTsrc, "", pruneGoMod)
if treeCanMatch("cmd") {
walkPkgs(filepath.Join(cfg.GOROOTsrc, "cmd"), "cmd", pruneGoMod)
@@ -120,7 +132,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
walkPkgs(ModRoot(), targetPrefix, pruneGoMod|pruneVendor)
walkPkgs(filepath.Join(ModRoot(), "vendor"), "", pruneVendor)
}
- return pkgs
+ return
}
for _, mod := range modules {
@@ -143,7 +155,7 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
var err error
root, isLocal, err = fetch(mod)
if err != nil {
- base.Errorf("go: %v", err)
+ m.AddError(err)
continue
}
modPrefix = mod.Path
@@ -156,5 +168,5 @@ func matchPackages(pattern string, tags map[string]bool, useStd bool, modules []
walkPkgs(root, modPrefix, prune)
}
- return pkgs
+ return
}
diff --git a/src/cmd/go/internal/mvs/mvs.go b/src/cmd/go/internal/mvs/mvs.go
index dd3b3ccb86..1f8eaa1f60 100644
--- a/src/cmd/go/internal/mvs/mvs.go
+++ b/src/cmd/go/internal/mvs/mvs.go
@@ -115,7 +115,21 @@ func (e *BuildListError) Error() string {
}
// BuildList returns the build list for the target module.
-// The first element is the target itself, with the remainder of the list sorted by path.
+//
+// target is the root vertex of a module requirement graph. For cmd/go, this is
+// typically the main module, but note that this algorithm is not intended to
+// be Go-specific: module paths and versions are treated as opaque values.
+//
+// reqs describes the module requirement graph and provides an opaque method
+// for comparing versions.
+//
+// BuildList traverses the graph and returns a list containing the highest
+// version for each visited module. The first element of the returned list is
+// target itself; reqs.Max requires target.Version to compare higher than all
+// other versions, so no other version can be selected. The remaining elements
+// of the list are sorted by path.
+//
+// See https://research.swtch.com/vgo-mvs for details.
func BuildList(target module.Version, reqs Reqs) ([]module.Version, error) {
return buildList(target, reqs, nil)
}
@@ -220,10 +234,9 @@ func buildList(target module.Version, reqs Reqs, upgrade func(module.Version) (m
// The final list is the minimum version of each module found in the graph.
if v := min[target.Path]; v != target.Version {
- // TODO(jayconrod): there is a special case in modload.mvsReqs.Max
- // that prevents us from selecting a newer version of a module
- // when the module has no version. This may only be the case for target.
- // Should we always panic when target has a version?
+ // target.Version will be "" for modload, the main client of MVS.
+ // "" denotes the main module, which has no version. However, MVS treats
+ // version strings as opaque, so "" is not a special value here.
// See golang.org/issue/31491, golang.org/issue/29773.
panic(fmt.Sprintf("mistake: chose version %q instead of target %+v", v, target)) // TODO: Don't panic.
}
diff --git a/src/cmd/go/internal/search/search.go b/src/cmd/go/internal/search/search.go
index b588c3e467..4efef24152 100644
--- a/src/cmd/go/internal/search/search.go
+++ b/src/cmd/go/internal/search/search.go
@@ -128,8 +128,11 @@ func (m *Match) MatchPackages() {
root += "cmd" + string(filepath.Separator)
}
err := filepath.Walk(root, func(path string, fi os.FileInfo, err error) error {
- if err != nil || path == src {
- return nil
+ if err != nil {
+ return err // Likely a permission error, which could interfere with matching.
+ }
+ if path == src {
+ return nil // GOROOT/src and GOPATH/src cannot contain packages.
}
want := true
@@ -261,7 +264,10 @@ func (m *Match) MatchDirs() {
}
err := filepath.Walk(dir, func(path string, fi os.FileInfo, err error) error {
- if err != nil || !fi.IsDir() {
+ if err != nil {
+ return err // Likely a permission error, which could interfere with matching.
+ }
+ if !fi.IsDir() {
return nil
}
top := false
diff --git a/src/cmd/go/internal/test/test.go b/src/cmd/go/internal/test/test.go
index 48a873e46b..873a76aa38 100644
--- a/src/cmd/go/internal/test/test.go
+++ b/src/cmd/go/internal/test/test.go
@@ -73,10 +73,10 @@ As part of building a test binary, go test runs go vet on the package
and its test source files to identify significant problems. If go vet
finds any problems, go test reports those and does not run the test
binary. Only a high-confidence subset of the default go vet checks are
-used. That subset is: 'atomic', 'bool', 'buildtags', 'nilfunc', and
-'printf'. You can see the documentation for these and other vet tests
-via "go doc cmd/vet". To disable the running of go vet, use the
--vet=off flag.
+used. That subset is: 'atomic', 'bool', 'buildtags', 'errorsas',
+'ifaceassert', 'nilfunc', 'printf', and 'stringintconv'. You can see
+the documentation for these and other vet tests via "go doc cmd/vet".
+To disable the running of go vet, use the -vet=off flag.
All test output and summary lines are printed to the go command's
standard output, even if the test printed them to its own standard
@@ -487,6 +487,8 @@ var (
pkgArgs []string
pkgs []*load.Package
+ testHelp bool // -help option passed to test via -args
+
testKillTimeout = 100 * 365 * 24 * time.Hour // backup alarm; defaults to about a century if no timeout is set
testCacheExpire time.Time // ignore cached test results before this time
@@ -532,7 +534,7 @@ func testNeedBinary() bool {
// testShowPass reports whether the output for a passing test should be shown.
func testShowPass() bool {
- return testV || (testList != "")
+ return testV || (testList != "") || testHelp
}
var defaultVetFlags = []string{
@@ -548,12 +550,14 @@ var defaultVetFlags = []string{
// "-copylocks",
"-errorsas",
// "-httpresponse",
+ "-ifaceassert",
// "-lostcancel",
// "-methods",
"-nilfunc",
"-printf",
// "-rangeloops",
// "-shift",
+ "-stringintconv",
// "-structtags",
// "-tests",
// "-unreachable",
diff --git a/src/cmd/go/internal/test/testflag.go b/src/cmd/go/internal/test/testflag.go
index 9a3042bfe7..1ff34f7445 100644
--- a/src/cmd/go/internal/test/testflag.go
+++ b/src/cmd/go/internal/test/testflag.go
@@ -333,6 +333,23 @@ func testFlags(args []string) (packageNames, passToTest []string) {
injectedFlags = append(injectedFlags, "-test.outputdir="+testOutputDir)
}
+ // If the user is explicitly passing -help or -h, show output
+ // of the test binary so that the help output is displayed
+ // even though the test will exit with success.
+ // This loop is imperfect: it will do the wrong thing for a case
+ // like -args -test.outputdir -help. Such cases are probably rare,
+ // and getting this wrong doesn't do too much harm.
+helpLoop:
+ for _, arg := range explicitArgs {
+ switch arg {
+ case "--":
+ break helpLoop
+ case "-h", "-help", "--help":
+ testHelp = true
+ break helpLoop
+ }
+ }
+
// Ensure that -race and -covermode are compatible.
if testCoverMode == "" {
testCoverMode = "set"
diff --git a/src/cmd/go/internal/web/http.go b/src/cmd/go/internal/web/http.go
index beb80c505d..e0509808d6 100644
--- a/src/cmd/go/internal/web/http.go
+++ b/src/cmd/go/internal/web/http.go
@@ -13,6 +13,7 @@ package web
import (
"crypto/tls"
+ "errors"
"fmt"
"mime"
"net/http"
@@ -47,6 +48,13 @@ var securityPreservingHTTPClient = &http.Client{
lastHop := via[len(via)-1].URL
return fmt.Errorf("redirected from secure URL %s to insecure URL %s", lastHop, req.URL)
}
+
+ // Go's http.DefaultClient allows 10 redirects before returning an error.
+ // The securityPreservingHTTPClient also uses this default policy to avoid
+ // Go command hangs.
+ if len(via) >= 10 {
+ return errors.New("stopped after 10 redirects")
+ }
return nil
},
}
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index 6ab3498c3e..071c9d2db9 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -2434,13 +2434,25 @@ func (b *Builder) gccSupportsFlag(compiler []string, flag string) bool {
if b.flagCache == nil {
b.flagCache = make(map[[2]string]bool)
}
+
+ tmp := os.DevNull
+ if runtime.GOOS == "windows" {
+ f, err := ioutil.TempFile(b.WorkDir, "")
+ if err != nil {
+ return false
+ }
+ f.Close()
+ tmp = f.Name()
+ defer os.Remove(tmp)
+ }
+
// We used to write an empty C file, but that gets complicated with
// go build -n. We tried using a file that does not exist, but that
// fails on systems with GCC version 4.2.1; that is the last GPLv2
// version of GCC, so some systems have frozen on it.
// Now we pass an empty file on stdin, which should work at least for
// GCC and clang.
- cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", os.DevNull)
+ cmdArgs := str.StringList(compiler, flag, "-c", "-x", "c", "-", "-o", tmp)
if cfg.BuildN || cfg.BuildX {
b.Showcmd(b.WorkDir, "%s || true", joinUnambiguously(cmdArgs))
if cfg.BuildN {
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 318d688d2e..f1d08e0268 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -168,7 +168,7 @@ func gcBackendConcurrency(gcflags []string) int {
CheckFlags:
for _, flag := range gcflags {
// Concurrent compilation is presumed incompatible with any gcflags,
- // except for a small whitelist of commonly used flags.
+ // except for known commonly used flags.
// If the user knows better, they can manually add their own -c to the gcflags.
switch flag {
case "-N", "-l", "-S", "-B", "-C", "-I":
diff --git a/src/cmd/go/internal/work/security.go b/src/cmd/go/internal/work/security.go
index 0ce1664c16..3ee68ac1b4 100644
--- a/src/cmd/go/internal/work/security.go
+++ b/src/cmd/go/internal/work/security.go
@@ -184,7 +184,9 @@ var validLinkerFlags = []*lazyregexp.Regexp{
re(`-Wl,--enable-new-dtags`),
re(`-Wl,--end-group`),
re(`-Wl,--(no-)?export-dynamic`),
+ re(`-Wl,-E`),
re(`-Wl,-framework,[^,@\-][^,]+`),
+ re(`-Wl,--hash-style=(sysv|gnu|both)`),
re(`-Wl,-headerpad_max_install_names`),
re(`-Wl,--no-undefined`),
re(`-Wl,-R([^@\-][^,@]*$)`),
@@ -200,6 +202,7 @@ var validLinkerFlags = []*lazyregexp.Regexp{
re(`-Wl,-undefined[=,]([^,@\-][^,]+)`),
re(`-Wl,-?-unresolved-symbols=[^,]+`),
re(`-Wl,--(no-)?warn-([^,]+)`),
+ re(`-Wl,-?-wrap[=,][^,@\-][^,]*`),
re(`-Wl,-z,(no)?execstack`),
re(`-Wl,-z,relro`),
diff --git a/src/cmd/go/internal/work/security_test.go b/src/cmd/go/internal/work/security_test.go
index 6b85c40b13..11e74f29c6 100644
--- a/src/cmd/go/internal/work/security_test.go
+++ b/src/cmd/go/internal/work/security_test.go
@@ -131,6 +131,7 @@ var goodLinkerFlags = [][]string{
{"-mtune=happybirthday"},
{"-pic"},
{"-pthread"},
+ {"-Wl,--hash-style=both"},
{"-Wl,-rpath,foo"},
{"-Wl,-rpath,$ORIGIN/foo"},
{"-Wl,-R", "/foo"},
@@ -208,6 +209,7 @@ var badLinkerFlags = [][]string{
{"-Wl,-framework", "-Wl,@Home"},
{"-Wl,-framework", "@Home"},
{"-Wl,-framework,Chocolate,@Home"},
+ {"-Wl,--hash-style=foo"},
{"-x", "--c"},
{"-x", "@obj"},
{"-Wl,-rpath,@foo"},
diff --git a/src/cmd/go/note_test.go b/src/cmd/go/note_test.go
index 089e2f3376..659366dcf9 100644
--- a/src/cmd/go/note_test.go
+++ b/src/cmd/go/note_test.go
@@ -53,7 +53,7 @@ func TestNoteReading(t *testing.T) {
// we've had trouble reading the notes generated by gold.
err := tg.doRun([]string{"build", "-ldflags", "-buildid=" + buildID + " -linkmode=external -extldflags=-fuse-ld=gold", "-o", tg.path("hello3.exe"), tg.path("hello.go")})
if err != nil {
- if tg.grepCountBoth("(invalid linker|gold|cannot find 'ld')") > 0 {
+ if tg.grepCountBoth("(invalid linker|gold|cannot find [‘']ld[’'])") > 0 {
// It's not an error if gold isn't there. gcc claims it "cannot find 'ld'" if
// ld.gold is missing, see issue #22340.
t.Log("skipping gold test")
diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go
index 8214488a59..2a4d2935b3 100644
--- a/src/cmd/go/proxy_test.go
+++ b/src/cmd/go/proxy_test.go
@@ -174,6 +174,25 @@ func proxyHandler(w http.ResponseWriter, r *http.Request) {
return
}
+ // Request for $GOPROXY/redirect/<count>/... goes to redirects.
+ if strings.HasPrefix(path, "redirect/") {
+ path = path[len("redirect/"):]
+ if j := strings.Index(path, "/"); j >= 0 {
+ count, err := strconv.Atoi(path[:j])
+ if err != nil {
+ return
+ }
+
+ // The last redirect.
+ if count <= 1 {
+ http.Redirect(w, r, fmt.Sprintf("/mod/%s", path[j+1:]), 302)
+ return
+ }
+ http.Redirect(w, r, fmt.Sprintf("/mod/redirect/%d/%s", count-1, path[j+1:]), 302)
+ return
+ }
+ }
+
// Request for $GOPROXY/sumdb/<name>/supported
// is checking whether it's OK to access sumdb via the proxy.
if path == "sumdb/"+testSumDBName+"/supported" {
diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go
index ebadce867b..2e8f18a897 100644
--- a/src/cmd/go/script_test.go
+++ b/src/cmd/go/script_test.go
@@ -10,6 +10,7 @@ package main_test
import (
"bytes"
"context"
+ "errors"
"fmt"
"go/build"
"internal/testenv"
@@ -77,13 +78,16 @@ type testScript struct {
stderr string // standard error from last 'go' command; for 'stderr' command
stopped bool // test wants to stop early
start time.Time // time phase started
- background []backgroundCmd // backgrounded 'exec' and 'go' commands
+ background []*backgroundCmd // backgrounded 'exec' and 'go' commands
}
type backgroundCmd struct {
- cmd *exec.Cmd
- wait <-chan struct{}
- want simpleStatus
+ want simpleStatus
+ args []string
+ cancel context.CancelFunc
+ done <-chan struct{}
+ err error
+ stdout, stderr strings.Builder
}
type simpleStatus string
@@ -126,6 +130,7 @@ func (ts *testScript) setup() {
"GOPROXY=" + proxyURL,
"GOPRIVATE=",
"GOROOT=" + testGOROOT,
+ "GOROOT_FINAL=" + os.Getenv("GOROOT_FINAL"), // causes spurious rebuilds and breaks the "stale" built-in if not propagated
"TESTGO_GOROOT=" + testGOROOT,
"GOSUMDB=" + testSumDBVerifierKey,
"GONOPROXY=",
@@ -193,10 +198,10 @@ func (ts *testScript) run() {
// before we print PASS. If we return early (e.g., due to a test failure),
// don't print anything about the processes that were still running.
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
for _, bg := range ts.background {
- <-bg.wait
+ <-bg.done
}
ts.background = nil
@@ -347,7 +352,7 @@ Script:
}
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
ts.cmdWait(success, nil)
@@ -633,40 +638,35 @@ func (ts *testScript) cmdExec(want simpleStatus, args []string) {
ts.fatalf("usage: exec program [args...] [&]")
}
- var err error
+ background := false
if len(args) > 0 && args[len(args)-1] == "&" {
- var cmd *exec.Cmd
- cmd, err = ts.execBackground(args[0], args[1:len(args)-1]...)
- if err == nil {
- wait := make(chan struct{})
- go func() {
- ctxWait(testCtx, cmd)
- close(wait)
- }()
- ts.background = append(ts.background, backgroundCmd{cmd, wait, want})
- }
- ts.stdout, ts.stderr = "", ""
- } else {
- ts.stdout, ts.stderr, err = ts.exec(args[0], args[1:]...)
- if ts.stdout != "" {
- fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
- }
- if ts.stderr != "" {
- fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
- }
- if err == nil && want == failure {
- ts.fatalf("unexpected command success")
- }
+ background = true
+ args = args[:len(args)-1]
}
+ bg, err := ts.startBackground(want, args[0], args[1:]...)
if err != nil {
- fmt.Fprintf(&ts.log, "[%v]\n", err)
- if testCtx.Err() != nil {
- ts.fatalf("test timed out while running command")
- } else if want == success {
- ts.fatalf("unexpected command failure")
- }
+ ts.fatalf("unexpected error starting command: %v", err)
}
+ if background {
+ ts.stdout, ts.stderr = "", ""
+ ts.background = append(ts.background, bg)
+ return
+ }
+
+ <-bg.done
+ ts.stdout = bg.stdout.String()
+ ts.stderr = bg.stderr.String()
+ if ts.stdout != "" {
+ fmt.Fprintf(&ts.log, "[stdout]\n%s", ts.stdout)
+ }
+ if ts.stderr != "" {
+ fmt.Fprintf(&ts.log, "[stderr]\n%s", ts.stderr)
+ }
+ if bg.err != nil {
+ fmt.Fprintf(&ts.log, "[%v]\n", bg.err)
+ }
+ ts.checkCmd(bg)
}
// exists checks that the list of files exists.
@@ -759,7 +759,7 @@ func (ts *testScript) cmdSkip(want simpleStatus, args []string) {
// Before we mark the test as skipped, shut down any background processes and
// make sure they have returned the correct status.
for _, bg := range ts.background {
- interruptProcess(bg.cmd.Process)
+ bg.cancel()
}
ts.cmdWait(success, nil)
@@ -932,34 +932,24 @@ func (ts *testScript) cmdWait(want simpleStatus, args []string) {
var stdouts, stderrs []string
for _, bg := range ts.background {
- <-bg.wait
+ <-bg.done
- args := append([]string{filepath.Base(bg.cmd.Args[0])}, bg.cmd.Args[1:]...)
- fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.cmd.ProcessState)
+ args := append([]string{filepath.Base(bg.args[0])}, bg.args[1:]...)
+ fmt.Fprintf(&ts.log, "[background] %s: %v\n", strings.Join(args, " "), bg.err)
- cmdStdout := bg.cmd.Stdout.(*strings.Builder).String()
+ cmdStdout := bg.stdout.String()
if cmdStdout != "" {
fmt.Fprintf(&ts.log, "[stdout]\n%s", cmdStdout)
stdouts = append(stdouts, cmdStdout)
}
- cmdStderr := bg.cmd.Stderr.(*strings.Builder).String()
+ cmdStderr := bg.stderr.String()
if cmdStderr != "" {
fmt.Fprintf(&ts.log, "[stderr]\n%s", cmdStderr)
stderrs = append(stderrs, cmdStderr)
}
- if bg.cmd.ProcessState.Success() {
- if bg.want == failure {
- ts.fatalf("unexpected command success")
- }
- } else {
- if testCtx.Err() != nil {
- ts.fatalf("test timed out while running command")
- } else if bg.want == success {
- ts.fatalf("unexpected command failure")
- }
- }
+ ts.checkCmd(bg)
}
ts.stdout = strings.Join(stdouts, "")
@@ -987,58 +977,176 @@ func (ts *testScript) check(err error) {
}
}
+func (ts *testScript) checkCmd(bg *backgroundCmd) {
+ select {
+ case <-bg.done:
+ default:
+ panic("checkCmd called when not done")
+ }
+
+ if bg.err == nil {
+ if bg.want == failure {
+ ts.fatalf("unexpected command success")
+ }
+ return
+ }
+
+ if errors.Is(bg.err, context.DeadlineExceeded) {
+ ts.fatalf("test timed out while running command")
+ }
+
+ if errors.Is(bg.err, context.Canceled) {
+ // The process was still running at the end of the test.
+ // The test must not depend on its exit status.
+ if bg.want != successOrFailure {
+ ts.fatalf("unexpected background command remaining at test end")
+ }
+ return
+ }
+
+ if bg.want == success {
+ ts.fatalf("unexpected command failure")
+ }
+}
+
// exec runs the given command line (an actual subprocess, not simulated)
// in ts.cd with environment ts.env and then returns collected standard output and standard error.
func (ts *testScript) exec(command string, args ...string) (stdout, stderr string, err error) {
- cmd := exec.Command(command, args...)
- cmd.Dir = ts.cd
- cmd.Env = append(ts.env, "PWD="+ts.cd)
- var stdoutBuf, stderrBuf strings.Builder
- cmd.Stdout = &stdoutBuf
- cmd.Stderr = &stderrBuf
- if err = cmd.Start(); err == nil {
- err = ctxWait(testCtx, cmd)
+ bg, err := ts.startBackground(success, command, args...)
+ if err != nil {
+ return "", "", err
}
- return stdoutBuf.String(), stderrBuf.String(), err
+ <-bg.done
+ return bg.stdout.String(), bg.stderr.String(), bg.err
}
-// execBackground starts the given command line (an actual subprocess, not simulated)
+// startBackground starts the given command line (an actual subprocess, not simulated)
// in ts.cd with environment ts.env.
-func (ts *testScript) execBackground(command string, args ...string) (*exec.Cmd, error) {
+func (ts *testScript) startBackground(want simpleStatus, command string, args ...string) (*backgroundCmd, error) {
+ done := make(chan struct{})
+ bg := &backgroundCmd{
+ want: want,
+ args: append([]string{command}, args...),
+ done: done,
+ cancel: func() {},
+ }
+
+ ctx := context.Background()
+ gracePeriod := 100 * time.Millisecond
+ if deadline, ok := ts.t.Deadline(); ok {
+ timeout := time.Until(deadline)
+ // If time allows, increase the termination grace period to 5% of the
+ // remaining time.
+ if gp := timeout / 20; gp > gracePeriod {
+ gracePeriod = gp
+ }
+
+ // Send the first termination signal with two grace periods remaining.
+ // If it still hasn't finished after the first period has elapsed,
+ // we'll escalate to os.Kill with a second period remaining until the
+ // test deadline..
+ timeout -= 2 * gracePeriod
+
+ if timeout <= 0 {
+ // The test has less than the grace period remaining. There is no point in
+ // even starting the command, because it will be terminated immediately.
+ // Save the expense of starting it in the first place.
+ bg.err = context.DeadlineExceeded
+ close(done)
+ return bg, nil
+ }
+
+ ctx, bg.cancel = context.WithTimeout(ctx, timeout)
+ }
+
cmd := exec.Command(command, args...)
cmd.Dir = ts.cd
cmd.Env = append(ts.env, "PWD="+ts.cd)
- var stdoutBuf, stderrBuf strings.Builder
- cmd.Stdout = &stdoutBuf
- cmd.Stderr = &stderrBuf
- return cmd, cmd.Start()
-}
-
-// ctxWait is like cmd.Wait, but terminates cmd with os.Interrupt if ctx becomes done.
-//
-// This differs from exec.CommandContext in that it prefers os.Interrupt over os.Kill.
-// (See https://golang.org/issue/21135.)
-func ctxWait(ctx context.Context, cmd *exec.Cmd) error {
- errc := make(chan error, 1)
- go func() { errc <- cmd.Wait() }()
-
- select {
- case err := <-errc:
- return err
- case <-ctx.Done():
- interruptProcess(cmd.Process)
- return <-errc
+ cmd.Stdout = &bg.stdout
+ cmd.Stderr = &bg.stderr
+ if err := cmd.Start(); err != nil {
+ bg.cancel()
+ return nil, err
}
+
+ go func() {
+ bg.err = waitOrStop(ctx, cmd, stopSignal(), gracePeriod)
+ close(done)
+ }()
+ return bg, nil
}
-// interruptProcess sends os.Interrupt to p if supported, or os.Kill otherwise.
-func interruptProcess(p *os.Process) {
- if err := p.Signal(os.Interrupt); err != nil {
+// stopSignal returns the appropriate signal to use to request that a process
+// stop execution.
+func stopSignal() os.Signal {
+ if runtime.GOOS == "windows" {
// Per https://golang.org/pkg/os/#Signal, “Interrupt is not implemented on
// Windows; using it with os.Process.Signal will return an error.”
// Fall back to Kill instead.
- p.Kill()
+ return os.Kill
+ }
+ return os.Interrupt
+}
+
+// waitOrStop waits for the already-started command cmd by calling its Wait method.
+//
+// If cmd does not return before ctx is done, waitOrStop sends it the given interrupt signal.
+// If killDelay is positive, waitOrStop waits that additional period for Wait to return before sending os.Kill.
+//
+// This function is copied from the one added to x/playground/internal in
+// http://golang.org/cl/228438.
+func waitOrStop(ctx context.Context, cmd *exec.Cmd, interrupt os.Signal, killDelay time.Duration) error {
+ if cmd.Process == nil {
+ panic("waitOrStop called with a nil cmd.Process — missing Start call?")
+ }
+ if interrupt == nil {
+ panic("waitOrStop requires a non-nil interrupt signal")
+ }
+
+ errc := make(chan error)
+ go func() {
+ select {
+ case errc <- nil:
+ return
+ case <-ctx.Done():
+ }
+
+ err := cmd.Process.Signal(interrupt)
+ if err == nil {
+ err = ctx.Err() // Report ctx.Err() as the reason we interrupted.
+ } else if err.Error() == "os: process already finished" {
+ errc <- nil
+ return
+ }
+
+ if killDelay > 0 {
+ timer := time.NewTimer(killDelay)
+ select {
+ // Report ctx.Err() as the reason we interrupted the process...
+ case errc <- ctx.Err():
+ timer.Stop()
+ return
+ // ...but after killDelay has elapsed, fall back to a stronger signal.
+ case <-timer.C:
+ }
+
+ // Wait still hasn't returned.
+ // Kill the process harder to make sure that it exits.
+ //
+ // Ignore any error: if cmd.Process has already terminated, we still
+ // want to send ctx.Err() (or the error from the Interrupt call)
+ // to properly attribute the signal that may have terminated it.
+ _ = cmd.Process.Kill()
+ }
+
+ errc <- err
+ }()
+
+ waitErr := cmd.Wait()
+ if interruptErr := <-errc; interruptErr != nil {
+ return interruptErr
}
+ return waitErr
}
// expand applies environment variable expansion to the string s.
diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README
index e22ddcaf2e..76d6651718 100644
--- a/src/cmd/go/testdata/script/README
+++ b/src/cmd/go/testdata/script/README
@@ -34,6 +34,7 @@ Scripts also have access to these other environment variables:
GOPATH=$WORK/gopath
GOPROXY=<local module proxy serving from cmd/go/testdata/mod>
GOROOT=<actual GOROOT>
+ GOROOT_FINAL=<actual GOROOT_FINAL>
TESTGO_GOROOT=<GOROOT used to build cmd/go, for use in tests that may change GOROOT>
HOME=/no-home
PATH=<actual PATH>
@@ -138,8 +139,9 @@ The commands are:
output and standard error of the previous command is cleared, but the output
of the background process is buffered — and checking of its exit status is
delayed — until the next call to 'wait', 'skip', or 'stop' or the end of the
- test. At the end of the test, any remaining background processes are
- terminated using os.Interrupt (if supported) or os.Kill.
+ test. If any background processes remain at the end of the test, they
+ are terminated using os.Interrupt (if supported) or os.Kill and the test
+ must not depend upon their exit status.
- [!] exists [-readonly] [-exec] file...
Each of the listed files or directories must (or must not) exist.
diff --git a/src/cmd/go/testdata/script/build_trimpath.txt b/src/cmd/go/testdata/script/build_trimpath.txt
index cfab80743e..ad78bcf2b2 100644
--- a/src/cmd/go/testdata/script/build_trimpath.txt
+++ b/src/cmd/go/testdata/script/build_trimpath.txt
@@ -1,5 +1,9 @@
[short] skip
+# If GOROOT_FINAL is set, 'go build -trimpath' bakes that into the resulting
+# binary instead of GOROOT. Explicitly unset it here.
+env GOROOT_FINAL=
+
# Set up two identical directories that can be used as GOPATH.
env GO111MODULE=on
mkdir $WORK/a/src/paths $WORK/b/src/paths
diff --git a/src/cmd/go/testdata/script/clean_cache_n.txt b/src/cmd/go/testdata/script/clean_cache_n.txt
new file mode 100644
index 0000000000..4497b36bc3
--- /dev/null
+++ b/src/cmd/go/testdata/script/clean_cache_n.txt
@@ -0,0 +1,25 @@
+# We're testing cache behavior, so start with a clean GOCACHE.
+env GOCACHE=$WORK/cache
+
+# Build something so that the cache gets populates
+go build main.go
+
+# Check that cache contains directories before running
+exists $GOCACHE/00
+
+# Run go clean -cache -n and ensure that directories weren't deleted
+go clean -cache -n
+exists $GOCACHE/00
+
+# Re-run go clean cache without the -n flag go ensure that directories were properly removed
+go clean -cache
+! exists $GOCACHE/00
+
+-- main.go --
+package main
+
+import "fmt"
+
+func main() {
+ fmt.Println("hello!")
+}
diff --git a/src/cmd/go/testdata/script/generate_env.txt b/src/cmd/go/testdata/script/generate_env.txt
index 0d3693fa33..2df1663376 100644
--- a/src/cmd/go/testdata/script/generate_env.txt
+++ b/src/cmd/go/testdata/script/generate_env.txt
@@ -1,7 +1,8 @@
# Install an env command because Windows and plan9 don't have it.
env GOBIN=$WORK/tmp/bin
go install env.go
-env PATH=$GOBIN${:}$PATH
+[plan9] env path=$GOBIN${:}$path
+[!plan9] env PATH=$GOBIN${:}$PATH
# Test generators have access to the environment
go generate ./printenv.go
diff --git a/src/cmd/go/testdata/script/goroot_executable.txt b/src/cmd/go/testdata/script/goroot_executable.txt
index 4e04bad69b..fdbcde06cb 100644
--- a/src/cmd/go/testdata/script/goroot_executable.txt
+++ b/src/cmd/go/testdata/script/goroot_executable.txt
@@ -2,6 +2,13 @@
mkdir $WORK/new/bin
+# In this test, we are specifically checking the logic for deriving
+# the value of GOROOT from runtime.GOROOT.
+# GOROOT_FINAL changes the default behavior of runtime.GOROOT,
+# and will thus cause the test to fail if it is set when our
+# new cmd/go is built.
+env GOROOT_FINAL=
+
go build -o $WORK/new/bin/go$GOEXE cmd/go &
go build -o $WORK/bin/check$GOEXE check.go &
wait
diff --git a/src/cmd/go/testdata/script/issue36000.txt b/src/cmd/go/testdata/script/issue36000.txt
new file mode 100644
index 0000000000..41732751ac
--- /dev/null
+++ b/src/cmd/go/testdata/script/issue36000.txt
@@ -0,0 +1,6 @@
+# Tests golang.org/issue/36000
+
+[!cgo] skip
+
+# go env with CGO flags should not make NUL file
+go env CGO_CFLAGS
diff --git a/src/cmd/go/testdata/script/list_case_collision.txt b/src/cmd/go/testdata/script/list_case_collision.txt
index f33afa857f..1b5f305587 100644
--- a/src/cmd/go/testdata/script/list_case_collision.txt
+++ b/src/cmd/go/testdata/script/list_case_collision.txt
@@ -20,6 +20,10 @@ stdout 'case-insensitive import collision'
! go build example/a/pkg example/a/Pkg
stderr 'case-insensitive import collision'
+# Test that the path reported with an indirect import is correct.
+[!darwin] [!windows] ! go build example/c
+[!darwin] [!windows] stderr '^package example/c\n\timports example/b: case-insensitive file name collision: "FILE.go" and "file.go"$'
+
-- example/a/a.go --
package p
import (
@@ -33,4 +37,8 @@ package pkg
-- example/b/file.go --
package b
-- example/b/FILE.go --
-package b \ No newline at end of file
+package b
+-- example/c/c.go --
+package c
+
+import _ "example/b"
diff --git a/src/cmd/go/testdata/script/list_dedup_packages.txt b/src/cmd/go/testdata/script/list_dedup_packages.txt
index ab7068cf15..ebd497b7e5 100644
--- a/src/cmd/go/testdata/script/list_dedup_packages.txt
+++ b/src/cmd/go/testdata/script/list_dedup_packages.txt
@@ -6,7 +6,7 @@ env GOPATH=$WORK/tmp/testdata
cd $WORK
# Check output of go list to ensure no duplicates
-go list xtestonly ./testdata/src/xtestonly/...
+go list xtestonly ./tmp/testdata/src/xtestonly/...
cmp stdout $WORK/gopath/src/wantstdout
-- wantstdout --
diff --git a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
index 604d8b4fe1..6e48d7b42c 100644
--- a/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
+++ b/src/cmd/go/testdata/script/list_gofile_in_goroot.txt
@@ -69,5 +69,8 @@ go 1.14
package foo
-- $WORK/goroot/src/fmt/fmt.go --
package fmt
+-- $WORK/goroot/src/cmd/README --
+This directory must exist in order for the 'cmd' pattern to have something to
+match against.
-- $GOPATH/src/foo.go --
package foo
diff --git a/src/cmd/go/testdata/script/list_permissions.txt b/src/cmd/go/testdata/script/list_permissions.txt
new file mode 100644
index 0000000000..f65896ca14
--- /dev/null
+++ b/src/cmd/go/testdata/script/list_permissions.txt
@@ -0,0 +1,84 @@
+env GO111MODULE=on
+
+# Establish baseline behavior, before mucking with file permissions.
+
+go list ./noread/...
+stdout '^example.com/noread$'
+
+go list example.com/noread/...
+stdout '^example.com/noread$'
+
+go list ./empty/...
+stderr 'matched no packages'
+
+[root] stop # Root typically ignores file permissions.
+
+# Make the directory ./noread unreadable, and verify that 'go list' reports an
+# explicit error for a pattern that should match it (rather than treating it as
+# equivalent to an empty directory).
+
+[windows] skip # Does not have Unix-style directory permissions.
+[plan9] skip # Might not have Unix-style directory permissions.
+
+chmod 000 noread
+
+# Check explicit paths.
+
+! go list ./noread
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+
+! go list example.com/noread
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+
+# Check filesystem-relative patterns.
+
+! go list ./...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ./...: '
+
+! go list ./noread/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ./noread/...: '
+
+
+# Check module-prefix patterns.
+
+! go list example.com/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern example.com/...: '
+
+! go list example.com/noread/...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern example.com/noread/...: '
+
+
+[short] stop
+
+# Check global patterns, which should still
+# fail due to errors in the local module.
+
+! go list all
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern all: '
+
+! go list ...
+! stdout '^example.com/noread$'
+! stderr 'matched no packages'
+stderr '^pattern ...: '
+
+
+-- go.mod --
+module example.com
+go 1.15
+-- noread/noread.go --
+// Package noread exists, but will be made unreadable.
+package noread
+-- empty/README.txt --
+This directory intentionally left empty.
diff --git a/src/cmd/go/testdata/script/mod_convert_dep.txt b/src/cmd/go/testdata/script/mod_convert_dep.txt
index 267c90eb3c..ad22aca5be 100644
--- a/src/cmd/go/testdata/script/mod_convert_dep.txt
+++ b/src/cmd/go/testdata/script/mod_convert_dep.txt
@@ -20,7 +20,6 @@ cd $WORK/gopkgdir/x
! go list .
stderr 'cannot find main module'
! stderr 'Gopkg.lock'
-! stderr 'go mod init'
-- $WORK/test/Gopkg.lock --
-- $WORK/test/x/x.go --
diff --git a/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt
new file mode 100644
index 0000000000..9cbe0d279d
--- /dev/null
+++ b/src/cmd/go/testdata/script/mod_get_too_many_redirects.txt
@@ -0,0 +1,10 @@
+env GO111MODULE=on
+env GOPROXYBASE=$GOPROXY
+env GOPROXY=$GOPROXYBASE/redirect/11
+env GOSUMDB=off
+
+! go get -d rsc.io/quote@v1.2.0
+stderr 'stopped after 10 redirects'
+
+env GOPROXY=$GOPROXYBASE/redirect/9
+go get -d rsc.io/quote@v1.2.0
diff --git a/src/cmd/go/testdata/script/mod_gomodcache.txt b/src/cmd/go/testdata/script/mod_gomodcache.txt
index 67a8f07b2c..b2143e2093 100644
--- a/src/cmd/go/testdata/script/mod_gomodcache.txt
+++ b/src/cmd/go/testdata/script/mod_gomodcache.txt
@@ -24,7 +24,8 @@ grep '{"Version":"v1.0.0","Time":"2018-02-14T00:45:20Z"}' $GOPATH/pkg/mod/cache/
# If neither GOMODCACHE or GOPATH are set, GOPATH defaults to the user's $HOME/go, so GOMODCACHE becomes $HOME/go/pkg/mod
[windows] env USERPROFILE=$WORK/home # Ensure USERPROFILE is a valid path (rather than /no-home/ so we don't run into the logic that "uninfers" GOPATH in cmd/go/main.go
-[!windows] env HOME=$WORK/home
+[plan9] env home=$WORK/home
+[!windows] [!plan9] env HOME=$WORK/home
env GOMODCACHE=
env GOPATH=
go env GOMODCACHE
diff --git a/src/cmd/go/testdata/script/mod_gonoproxy.txt b/src/cmd/go/testdata/script/mod_gonoproxy.txt
index 2bd94cdee0..a9e0ca4010 100644
--- a/src/cmd/go/testdata/script/mod_gonoproxy.txt
+++ b/src/cmd/go/testdata/script/mod_gonoproxy.txt
@@ -10,7 +10,7 @@ env GOSUMDB=$sumdb' '$proxy/sumdb-wrong
! go get rsc.io/quote
stderr 'SECURITY ERROR'
-# but GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text
+# GONOSUMDB bypasses sumdb, for rsc.io/quote, rsc.io/sampler, golang.org/x/text
env GONOSUMDB='*/quote,*/*mple*,golang.org/x'
go get rsc.io/quote
rm go.sum
@@ -18,7 +18,18 @@ env GOPRIVATE='*/quote,*/*mple*,golang.org/x'
env GONOPROXY=none # that is, proxy all despite GOPRIVATE
go get rsc.io/quote
-# and GONOPROXY bypasses proxy
+# When GOPROXY is not empty but contains no entries, an error should be reported.
+env GOPROXY=','
+! go get golang.org/x/text
+stderr '^go get golang.org/x/text: GOPROXY list is not the empty string, but contains no entries$'
+
+# When GOPROXY=off, fetching modules not matched by GONOPROXY fails.
+env GONOPROXY=*/fortune
+env GOPROXY=off
+! go get golang.org/x/text
+stderr '^go get golang.org/x/text: module lookup disabled by GOPROXY=off$'
+
+# GONOPROXY bypasses proxy
[!net] skip
[!exec:git] skip
env GOPRIVATE=none
diff --git a/src/cmd/go/testdata/script/script_wait.txt b/src/cmd/go/testdata/script/script_wait.txt
index 3cd4ded9dd..acaccfe043 100644
--- a/src/cmd/go/testdata/script/script_wait.txt
+++ b/src/cmd/go/testdata/script/script_wait.txt
@@ -19,6 +19,7 @@ wait
stdout 'foo\nbar'
# The end of the test should interrupt or kill any remaining background
-# programs.
-[!exec:sleep] skip
-! exec sleep 86400 &
+# programs, but that should not cause the test to fail if it does not
+# care about the exit status of those programs.
+[!exec:sleep] stop
+? exec sleep 86400 &
diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt
new file mode 100644
index 0000000000..6031eadd0a
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_benchmark_chatty_fail.txt
@@ -0,0 +1,32 @@
+# Run chatty tests. Assert on CONT lines.
+! go test chatty_test.go -v -bench . chatty_bench
+
+# Sanity check that output occurs.
+stdout -count=2 'this is sub-0'
+stdout -count=2 'this is sub-1'
+stdout -count=2 'this is sub-2'
+stdout -count=1 'error from sub-0'
+stdout -count=1 'error from sub-1'
+stdout -count=1 'error from sub-2'
+
+# Benchmarks should not print CONT.
+! stdout CONT
+
+-- chatty_test.go --
+package chatty_bench
+
+import (
+ "testing"
+ "fmt"
+)
+
+func BenchmarkChatty(b *testing.B) {
+ for i := 0; i < 3; i++ {
+ b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) {
+ for j := 0; j < 2; j++ {
+ b.Logf("this is sub-%d", i)
+ }
+ b.Errorf("error from sub-%d", i)
+ })
+ }
+} \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt
new file mode 100644
index 0000000000..a1c0d6545a
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_benchmark_chatty_success.txt
@@ -0,0 +1,29 @@
+# Run chatty tests. Assert on CONT lines.
+go test chatty_test.go -v -bench . chatty_bench
+
+# Sanity check that output happens. We don't provide -count because the amount
+# of output is variable.
+stdout 'this is sub-0'
+stdout 'this is sub-1'
+stdout 'this is sub-2'
+
+# Benchmarks should not print CONT.
+! stdout CONT
+
+-- chatty_test.go --
+package chatty_bench
+
+import (
+ "testing"
+ "fmt"
+)
+
+func BenchmarkChatty(b *testing.B) {
+ for i := 0; i < 3; i++ {
+ b.Run(fmt.Sprintf("sub-%d", i), func(b *testing.B) {
+ for j := 0; j < 2; j++ {
+ b.Logf("this is sub-%d", i)
+ }
+ })
+ }
+} \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/test_chatty_fail.txt b/src/cmd/go/testdata/script/test_chatty_fail.txt
new file mode 100644
index 0000000000..a5ef559c77
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_chatty_fail.txt
@@ -0,0 +1,32 @@
+# Run chatty tests. Assert on CONT lines.
+! go test chatty_test.go -v
+
+# Sanity check that output occurs.
+stdout -count=2 'this is sub-0'
+stdout -count=2 'this is sub-1'
+stdout -count=2 'this is sub-2'
+stdout -count=1 'error from sub-0'
+stdout -count=1 'error from sub-1'
+stdout -count=1 'error from sub-2'
+
+# Non-parallel tests should not print CONT.
+! stdout CONT
+
+-- chatty_test.go --
+package chatty_test
+
+import (
+ "testing"
+ "fmt"
+)
+
+func TestChatty(t *testing.T) {
+ for i := 0; i < 3; i++ {
+ t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) {
+ for j := 0; j < 2; j++ {
+ t.Logf("this is sub-%d", i)
+ }
+ t.Errorf("error from sub-%d", i)
+ })
+ }
+} \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt
new file mode 100644
index 0000000000..3f7360b659
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_chatty_parallel_fail.txt
@@ -0,0 +1,58 @@
+# Run parallel chatty tests. Assert on CONT lines. This test makes sure that
+# multiple parallel outputs have the appropriate CONT lines between them.
+! go test -parallel 3 chatty_parallel_test.go -v
+
+stdout -count=1 '^=== CONT TestChattyParallel/sub-0\n chatty_parallel_test.go:38: error from sub-0$'
+stdout -count=1 '^=== CONT TestChattyParallel/sub-1\n chatty_parallel_test.go:38: error from sub-1$'
+stdout -count=1 '^=== CONT TestChattyParallel/sub-2\n chatty_parallel_test.go:38: error from sub-2$'
+
+# Run parallel chatty tests with -json. Assert on CONT lines as above - make
+# sure there are CONT lines before each output line.
+! go test -json -parallel 3 chatty_parallel_test.go -v
+stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":"=== CONT TestChattyParallel/sub-0\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:38: error from sub-0\\n"}'
+stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":"=== CONT TestChattyParallel/sub-1\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:38: error from sub-1\\n"}'
+stdout -count=1 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:38: error from sub-2\\n"}'
+
+-- chatty_parallel_test.go --
+package chatty_paralell_test
+
+import (
+ "testing"
+ "fmt"
+ "flag"
+)
+
+// This test ensures the the order of CONT lines in parallel chatty tests.
+func TestChattyParallel(t *testing.T) {
+ t.Parallel()
+
+ // The number of concurrent tests running. This is closely tied to the
+ // -parallel test flag, so we grab it from the flag rather than setting it
+ // to some constant.
+ parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int)
+
+ // ready is a synchronization mechanism that causes subtests to execute
+ // round robin.
+ ready := make([]chan bool, parallel)
+ for i := range ready {
+ ready[i] = make(chan bool, 1)
+ }
+ ready[0] <- true
+
+ for i := range ready {
+ i := i
+ t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) {
+ t.Parallel()
+
+ // Some basic log output to precede the failures.
+ <-ready[i]
+ t.Logf("this is sub-%d", i)
+ ready[(i+1)%len(ready)] <- true
+
+ // The actual failure messages we care about.
+ <-ready[i]
+ t.Errorf("error from sub-%d", i)
+ ready[(i+1)%len(ready)] <- true
+ })
+ }
+}
diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt
new file mode 100644
index 0000000000..4a86d74f19
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_chatty_parallel_success.txt
@@ -0,0 +1,52 @@
+# Run parallel chatty tests. Assert on CONT lines. This test makes sure that
+# multiple parallel outputs have the appropriate CONT lines between them.
+go test -parallel 3 chatty_parallel_test.go -v
+stdout -count=2 '^=== CONT TestChattyParallel/sub-0\n chatty_parallel_test.go:32: this is sub-0$'
+stdout -count=2 '^=== CONT TestChattyParallel/sub-1\n chatty_parallel_test.go:32: this is sub-1$'
+stdout -count=2 '^=== CONT TestChattyParallel/sub-2\n chatty_parallel_test.go:32: this is sub-2$'
+
+# Run parallel chatty tests with -json. Assert on CONT lines as above - make
+# sure there are CONT lines before each output line.
+go test -json -parallel 3 chatty_parallel_test.go -v
+stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":"=== CONT TestChattyParallel/sub-0\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-0","Output":" chatty_parallel_test.go:32: this is sub-0\\n"}'
+stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":"=== CONT TestChattyParallel/sub-1\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-1","Output":" chatty_parallel_test.go:32: this is sub-1\\n"}'
+stdout -count=2 '{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":"=== CONT TestChattyParallel/sub-2\\n"}\n{"Time":"[0-9TZ:.+-]{20,40}","Action":"output","Package":"command-line-arguments","Test":"TestChattyParallel/sub-2","Output":" chatty_parallel_test.go:32: this is sub-2\\n"}'
+
+-- chatty_parallel_test.go --
+package chatty_paralell_test
+
+import (
+ "testing"
+ "fmt"
+ "flag"
+)
+
+// This test ensures the the order of CONT lines in parallel chatty tests.
+func TestChattyParallel(t *testing.T) {
+ t.Parallel()
+
+ // The number of concurrent tests running. This is closely tied to the
+ // -parallel test flag, so we grab it from the flag rather than setting it
+ // to some constant.
+ parallel := flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int)
+
+ // ready is a synchronization mechanism that causes subtests to execute
+ // round robin.
+ ready := make([]chan bool, parallel)
+ for i := range ready {
+ ready[i] = make(chan bool, 1)
+ }
+ ready[0] <- true
+
+ for i := range ready {
+ i := i
+ t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) {
+ t.Parallel()
+ for j := 0; j < 2; j++ {
+ <-ready[i]
+ t.Logf("this is sub-%d", i)
+ ready[(i+1)%len(ready)] <- true
+ }
+ })
+ }
+}
diff --git a/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt
new file mode 100644
index 0000000000..5952a87bea
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_chatty_parallel_success_sleepy.txt
@@ -0,0 +1,39 @@
+# Run parallel chatty tests. Assert on CONT lines. This test makes sure that
+# multiple parallel outputs have the appropriate CONT lines between them.
+go test -parallel 3 chatty_parallel_test.go -v
+
+stdout '--- PASS: TestFast \([0-9.]{4}s\)\n=== CONT TestSlow\n chatty_parallel_test.go:31: this is the second TestSlow log\n--- PASS: TestSlow \([0-9.]{4}s\)'
+
+-- chatty_parallel_test.go --
+package chatty_paralell_test
+
+import (
+ "testing"
+ "time"
+)
+
+var (
+ run = make(chan struct{})
+ afterFirstLog = make(chan struct{})
+ afterPass = make(chan struct{})
+)
+
+func TestFast(t *testing.T) {
+ t.Parallel()
+
+ <-afterFirstLog
+ t.Cleanup(func() {
+ close(afterPass)
+ })
+}
+
+func TestSlow(t *testing.T) {
+ t.Parallel()
+
+ t.Logf("this is the first TestSlow log")
+ close(afterFirstLog)
+
+ <-afterPass
+ time.Sleep(100 * time.Millisecond)
+ t.Logf("this is the second TestSlow log")
+}
diff --git a/src/cmd/go/testdata/script/test_chatty_success.txt b/src/cmd/go/testdata/script/test_chatty_success.txt
new file mode 100644
index 0000000000..8bfa569f80
--- /dev/null
+++ b/src/cmd/go/testdata/script/test_chatty_success.txt
@@ -0,0 +1,27 @@
+# Run chatty tests. Assert on CONT lines.
+go test chatty_test.go -v
+
+# Non-parallel tests should not print CONT.
+! stdout CONT
+
+# The assertion is condensed into one line so that it precisely matches output,
+# rather than skipping lines and allow rogue CONT lines.
+stdout '=== RUN TestChatty\n=== RUN TestChatty/sub-0\n chatty_test.go:12: this is sub-0\n chatty_test.go:12: this is sub-0\n=== RUN TestChatty/sub-1\n chatty_test.go:12: this is sub-1\n chatty_test.go:12: this is sub-1\n=== RUN TestChatty/sub-2\n chatty_test.go:12: this is sub-2\n chatty_test.go:12: this is sub-2\n--- PASS: TestChatty'
+
+-- chatty_test.go --
+package chatty_test
+
+import (
+ "testing"
+ "fmt"
+)
+
+func TestChatty(t *testing.T) {
+ for i := 0; i < 3; i++ {
+ t.Run(fmt.Sprintf("sub-%d", i), func(t *testing.T) {
+ for j := 0; j < 2; j++ {
+ t.Logf("this is sub-%d", i)
+ }
+ })
+ }
+} \ No newline at end of file
diff --git a/src/cmd/go/testdata/script/test_flags.txt b/src/cmd/go/testdata/script/test_flags.txt
index 226b8d1315..d38e37f238 100644
--- a/src/cmd/go/testdata/script/test_flags.txt
+++ b/src/cmd/go/testdata/script/test_flags.txt
@@ -30,23 +30,23 @@ exists ./cover.out
# with the 'test.' prefix in the GOFLAGS entry...
env GOFLAGS='-test.timeout=24h0m0s -count=1'
go test -v -x ./x
-stdout 'TestLogTimeout: .*: 24h0m0s$'
+stdout '.*: 24h0m0s$'
stderr '-test.count=1'
# ...or without.
env GOFLAGS='-timeout=24h0m0s -count=1'
go test -v -x ./x
-stdout 'TestLogTimeout: .*: 24h0m0s$'
+stdout '.*: 24h0m0s$'
stderr '-test.count=1'
# Arguments from the command line should override GOFLAGS...
go test -v -x -timeout=25h0m0s ./x
-stdout 'TestLogTimeout: .*: 25h0m0s$'
+stdout '.*: 25h0m0s$'
stderr '-test.count=1'
# ...even if they use a different flag name.
go test -v -x -test.timeout=26h0m0s ./x
-stdout 'TestLogTimeout: .*: 26h0m0s$'
+stdout '.*: 26h0m0s$'
stderr '-test\.timeout=26h0m0s'
! stderr 'timeout=24h0m0s'
stderr '-test.count=1'
@@ -57,6 +57,10 @@ stderr -count=1 'invalid value "walrus" for flag -covermode: valid modes are .*$
stderr '^usage: go test .*$'
stderr '^Run ''go help test'' and ''go help testflag'' for details.$'
+# Passing -help to the test binary should show flag help.
+go test ./x -args -help
+stdout 'usage_message'
+
# -covermode, -coverpkg, and -coverprofile should imply -cover
go test -covermode=set ./x
stdout '\s+coverage:\s+'
@@ -98,6 +102,8 @@ import (
"testing"
)
+var _ = flag.String("usage_message", "", "dummy flag to check usage message")
+
func TestLogTimeout(t *testing.T) {
t.Log(flag.Lookup("test.timeout").Value)
}
diff --git a/src/cmd/go/testdata/script/test_regexps.txt b/src/cmd/go/testdata/script/test_regexps.txt
index 39dedbf06f..a616195cab 100644
--- a/src/cmd/go/testdata/script/test_regexps.txt
+++ b/src/cmd/go/testdata/script/test_regexps.txt
@@ -4,28 +4,28 @@ go test -cpu=1 -run=X/Y -bench=X/Y -count=2 -v testregexp
# TestX is run, twice
stdout -count=2 '^=== RUN TestX$'
-stdout -count=2 '^ TestX: x_test.go:6: LOG: X running$'
+stdout -count=2 '^ x_test.go:6: LOG: X running$'
# TestX/Y is run, twice
stdout -count=2 '^=== RUN TestX/Y$'
-stdout -count=2 '^ TestX/Y: x_test.go:8: LOG: Y running$'
+stdout -count=2 '^ x_test.go:8: LOG: Y running$'
# TestXX is run, twice
stdout -count=2 '^=== RUN TestXX$'
-stdout -count=2 '^ TestXX: z_test.go:10: LOG: XX running'
+stdout -count=2 '^ z_test.go:10: LOG: XX running'
# TestZ is not run
! stdout '^=== RUN TestZ$'
# BenchmarkX is run with N=1 once, only to discover what sub-benchmarks it has,
# and should not print a final summary line.
-stdout -count=1 '^\s+BenchmarkX: x_test.go:13: LOG: X running N=1$'
+stdout -count=1 '^ x_test.go:13: LOG: X running N=1$'
! stdout '^\s+BenchmarkX: x_test.go:13: LOG: X running N=\d\d+'
! stdout 'BenchmarkX\s+\d+'
# Same for BenchmarkXX.
-stdout -count=1 '^\s+BenchmarkXX: z_test.go:18: LOG: XX running N=1$'
-! stdout '^\s+BenchmarkXX: z_test.go:18: LOG: XX running N=\d\d+'
+stdout -count=1 '^ z_test.go:18: LOG: XX running N=1$'
+! stdout '^ z_test.go:18: LOG: XX running N=\d\d+'
! stdout 'BenchmarkXX\s+\d+'
# BenchmarkX/Y is run in full twice due to -count=2.
@@ -33,7 +33,7 @@ stdout -count=1 '^\s+BenchmarkXX: z_test.go:18: LOG: XX running N=1$'
# but may cap out at N=1e9.
# We don't actually care what the final iteration count is, but it should be
# a large number, and the last iteration count prints right before the results.
-stdout -count=2 '^\s+BenchmarkX/Y: x_test.go:15: LOG: Y running N=[1-9]\d{4,}\nBenchmarkX/Y\s+\d+'
+stdout -count=2 '^ x_test.go:15: LOG: Y running N=[1-9]\d{4,}\nBenchmarkX/Y\s+\d+'
-- testregexp/x_test.go --
package x
diff --git a/src/cmd/internal/goobj/goobj_test.go b/src/cmd/internal/goobj/goobj_test.go
index 9f827c6a32..4a4d35a413 100644
--- a/src/cmd/internal/goobj/goobj_test.go
+++ b/src/cmd/internal/goobj/goobj_test.go
@@ -17,7 +17,6 @@ import (
"os/exec"
"path/filepath"
"runtime"
- "strings"
"testing"
)
@@ -151,14 +150,6 @@ func buildGoobj() error {
return nil
}
-// Check that a symbol has a given name, accepting both
-// new and old objects.
-// TODO(go115newobj): remove.
-func matchSymName(symname, want string) bool {
- return symname == want ||
- strings.HasPrefix(symname, want+"#") // new style, with index
-}
-
func TestParseGoobj(t *testing.T) {
path := go1obj
@@ -177,7 +168,7 @@ func TestParseGoobj(t *testing.T) {
}
var found bool
for _, s := range p.Syms {
- if matchSymName(s.Name, "mypkg.go1") {
+ if s.Name == "mypkg.go1" {
found = true
break
}
@@ -206,10 +197,10 @@ func TestParseArchive(t *testing.T) {
var found1 bool
var found2 bool
for _, s := range p.Syms {
- if matchSymName(s.Name, "mypkg.go1") {
+ if s.Name == "mypkg.go1" {
found1 = true
}
- if matchSymName(s.Name, "mypkg.go2") {
+ if s.Name == "mypkg.go2" {
found2 = true
}
}
@@ -242,10 +233,10 @@ func TestParseCGOArchive(t *testing.T) {
var found1 bool
var found2 bool
for _, s := range p.Syms {
- if matchSymName(s.Name, "mycgo.go1") {
+ if s.Name == "mycgo.go1" {
found1 = true
}
- if matchSymName(s.Name, "mycgo.go2") {
+ if s.Name == "mycgo.go2" {
found2 = true
}
}
diff --git a/src/cmd/internal/goobj/readnew.go b/src/cmd/internal/goobj/readnew.go
index 3e710576b6..7a84b91d3a 100644
--- a/src/cmd/internal/goobj/readnew.go
+++ b/src/cmd/internal/goobj/readnew.go
@@ -7,7 +7,6 @@ package goobj
import (
"cmd/internal/goobj2"
"cmd/internal/objabi"
- "fmt"
"strings"
)
@@ -31,7 +30,13 @@ func (r *objReader) readNew() {
// Ignore fingerprint (for tools like objdump which only reads one object).
}
- pkglist := rr.Pkglist()
+ // Name of referenced indexed symbols.
+ nrefName := rr.NRefName()
+ refNames := make(map[goobj2.SymRef]string, nrefName)
+ for i := 0; i < nrefName; i++ {
+ rn := rr.RefName(i)
+ refNames[rn.Sym()] = rn.Name(rr)
+ }
abiToVer := func(abi uint16) int64 {
var vers int64
@@ -58,10 +63,7 @@ func (r *objReader) readNew() {
case goobj2.PkgIdxSelf:
i = int(s.SymIdx)
default:
- // Symbol from other package, referenced by index.
- // We don't know the name. Use index.
- pkg := pkglist[p]
- return SymID{fmt.Sprintf("%s.#%d", pkg, s.SymIdx), 0}
+ return SymID{refNames[s], 0}
}
sym := rr.Sym(i)
return SymID{sym.Name(rr), abiToVer(sym.ABI())}
@@ -72,7 +74,6 @@ func (r *objReader) readNew() {
// Symbols
pcdataBase := start + rr.PcdataBase()
n := rr.NSym() + rr.NNonpkgdef() + rr.NNonpkgref()
- npkgdef := rr.NSym()
ndef := rr.NSym() + rr.NNonpkgdef()
for i := 0; i < n; i++ {
osym := rr.Sym(i)
@@ -83,10 +84,6 @@ func (r *objReader) readNew() {
// prefix for the package in which the object file has been found.
// Expand it.
name := strings.ReplaceAll(osym.Name(rr), `"".`, r.pkgprefix)
- if i < npkgdef {
- // Indexed symbol. Attach index to the name.
- name += fmt.Sprintf("#%d", i)
- }
symID := SymID{Name: name, Version: abiToVer(osym.ABI())}
r.p.SymRefs = append(r.p.SymRefs, symID)
diff --git a/src/cmd/internal/goobj2/objfile.go b/src/cmd/internal/goobj2/objfile.go
index ab07624563..7f728e4f76 100644
--- a/src/cmd/internal/goobj2/objfile.go
+++ b/src/cmd/internal/goobj2/objfile.go
@@ -73,6 +73,14 @@ import (
// Data [...]byte
// Pcdata [...]byte
//
+// // blocks only used by tools (objdump, nm)
+//
+// RefNames [...]struct { // referenced symbol names
+// Sym symRef
+// Name string
+// // TODO: include ABI version as well?
+// }
+//
// string is encoded as is a uint32 length followed by a uint32 offset
// that points to the corresponding string bytes.
//
@@ -152,6 +160,8 @@ const (
BlkAux
BlkData
BlkPcdata
+ BlkRefName
+ BlkEnd
NBlk
)
@@ -369,6 +379,37 @@ func (a *Aux) Write(w *Writer) { w.Bytes(a[:]) }
// for testing
func (a *Aux) fromBytes(b []byte) { copy(a[:], b) }
+// Referenced symbol name.
+//
+// Serialized format:
+// RefName struct {
+// Sym symRef
+// Name string
+// }
+type RefName [RefNameSize]byte
+
+const RefNameSize = 8 + stringRefSize
+
+func (n *RefName) Sym() SymRef {
+ return SymRef{binary.LittleEndian.Uint32(n[:]), binary.LittleEndian.Uint32(n[4:])}
+}
+func (n *RefName) Name(r *Reader) string {
+ len := binary.LittleEndian.Uint32(n[8:])
+ off := binary.LittleEndian.Uint32(n[12:])
+ return r.StringAt(off, len)
+}
+
+func (n *RefName) SetSym(x SymRef) {
+ binary.LittleEndian.PutUint32(n[:], x.PkgIdx)
+ binary.LittleEndian.PutUint32(n[4:], x.SymIdx)
+}
+func (n *RefName) SetName(x string, w *Writer) {
+ binary.LittleEndian.PutUint32(n[8:], uint32(len(x)))
+ binary.LittleEndian.PutUint32(n[12:], w.stringOff(x))
+}
+
+func (n *RefName) Write(w *Writer) { w.Bytes(n[:]) }
+
type Writer struct {
wr *bio.Writer
stringMap map[string]uint32
@@ -666,6 +707,18 @@ func (r *Reader) PcdataBase() uint32 {
return r.h.Offsets[BlkPcdata]
}
+// NRefName returns the number of referenced symbol names.
+func (r *Reader) NRefName() int {
+ return int(r.h.Offsets[BlkRefName+1]-r.h.Offsets[BlkRefName]) / RefNameSize
+}
+
+// RefName returns a pointer to the i-th referenced symbol name.
+// Note: here i is not a local symbol index, just a counter.
+func (r *Reader) RefName(i int) *RefName {
+ off := r.h.Offsets[BlkRefName] + uint32(i*RefNameSize)
+ return (*RefName)(unsafe.Pointer(&r.b[off]))
+}
+
// ReadOnly returns whether r.BytesAt returns read-only bytes.
func (r *Reader) ReadOnly() bool {
return r.readonly
diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go
index 5d73edd318..2e6167322e 100644
--- a/src/cmd/internal/moddeps/moddeps_test.go
+++ b/src/cmd/internal/moddeps/moddeps_test.go
@@ -36,7 +36,7 @@ func findGorootModules(t *testing.T) []gorootModule {
if err != nil {
return err
}
- if info.Name() == "vendor" || info.Name() == "testdata" {
+ if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") {
return filepath.SkipDir
}
if path == filepath.Join(runtime.GOROOT(), "pkg") {
diff --git a/src/cmd/internal/obj/arm/a.out.go b/src/cmd/internal/obj/arm/a.out.go
index 51e6163181..a1d9e28b96 100644
--- a/src/cmd/internal/obj/arm/a.out.go
+++ b/src/cmd/internal/obj/arm/a.out.go
@@ -1,5 +1,5 @@
// Inferno utils/5c/5.out.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/5.out.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/5.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/arm/asm5.go b/src/cmd/internal/obj/arm/asm5.go
index b398de2dac..f66f8aaf84 100644
--- a/src/cmd/internal/obj/arm/asm5.go
+++ b/src/cmd/internal/obj/arm/asm5.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/arm/list5.go b/src/cmd/internal/obj/arm/list5.go
index 2654312b89..6d630f61de 100644
--- a/src/cmd/internal/obj/arm/list5.go
+++ b/src/cmd/internal/obj/arm/list5.go
@@ -1,5 +1,5 @@
// Inferno utils/5c/list.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/list.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/arm/obj5.go b/src/cmd/internal/obj/arm/obj5.go
index a895929b62..008118c47b 100644
--- a/src/cmd/internal/obj/arm/obj5.go
+++ b/src/cmd/internal/obj/arm/obj5.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/5c/swt.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5c/swt.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5c/swt.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go
index 9a1908a655..df17729a76 100644
--- a/src/cmd/internal/obj/arm64/asm7.go
+++ b/src/cmd/internal/obj/arm64/asm7.go
@@ -460,7 +460,6 @@ var optab = []Optab{
{AFCVTZSD, C_FREG, C_NONE, C_NONE, C_REG, 29, 4, 0, 0, 0},
{ASCVTFD, C_REG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
{AFCVTSD, C_FREG, C_NONE, C_NONE, C_FREG, 29, 4, 0, 0, 0},
- {AVCNT, C_ARNG, C_NONE, C_NONE, C_ARNG, 29, 4, 0, 0, 0},
{AVMOV, C_ELEM, C_NONE, C_NONE, C_REG, 73, 4, 0, 0, 0},
{AVMOV, C_ELEM, C_NONE, C_NONE, C_ELEM, 92, 4, 0, 0, 0},
{AVMOV, C_ELEM, C_NONE, C_NONE, C_VREG, 80, 4, 0, 0, 0},
@@ -1639,12 +1638,12 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
}
if isaddcon(int64(v)) {
if v <= 0xFFF {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_ABCON0
}
return C_ADDCON0
}
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_ABCON
}
if movcon(int64(v)) >= 0 {
@@ -1658,7 +1657,7 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t := movcon(int64(v))
if t >= 0 {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_MBCON
}
return C_MOVCON
@@ -1666,13 +1665,13 @@ func (c *ctxt7) con32class(a *obj.Addr) int {
t = movcon(int64(^v))
if t >= 0 {
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_MBCON
}
return C_MOVCON
}
- if isbitcon(uint64(v)) {
+ if isbitcon(uint64(a.Offset)) {
return C_BITCON
}
@@ -2773,6 +2772,7 @@ func buildop(ctxt *obj.Link) {
oprangeset(AVSRI, t)
case AVREV32:
+ oprangeset(AVCNT, t)
oprangeset(AVRBIT, t)
oprangeset(AVREV64, t)
oprangeset(AVREV16, t)
@@ -4523,7 +4523,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
c.ctxt.Diag("invalid arrangement: %v\n", p)
}
- if (p.As == AVMOV || p.As == AVRBIT) && (af != ARNG_16B && af != ARNG_8B) {
+ if (p.As == AVMOV || p.As == AVRBIT || p.As == AVCNT) && (af != ARNG_16B && af != ARNG_8B) {
c.ctxt.Diag("invalid arrangement: %v", p)
}
diff --git a/src/cmd/internal/obj/arm64/doc.go b/src/cmd/internal/obj/arm64/doc.go
index df516b6382..7515217544 100644
--- a/src/cmd/internal/obj/arm64/doc.go
+++ b/src/cmd/internal/obj/arm64/doc.go
@@ -22,7 +22,8 @@ using different register names.
Examples:
MOVD.P -8(R10), R8 <=> ldr x8, [x10],#-8
- MOVB.W 16(R16), R10 <=> ldr x10, [x16,#16]!
+ MOVB.W 16(R16), R10 <=> ldrsb x10, [x16,#16]!
+ MOVBU.W 16(R16), R10 <=> ldrb x10, [x16,#16]!
3. Go uses a series of MOV instructions as load and store.
@@ -57,7 +58,7 @@ must be a power of 2 and in the range of [8, 2048].
PCALIGN $1024
MOVD $3, R1 // This instruction is aligned with 1024 bytes.
-PCALING also changes the function alignment. If a function has one or more PCALIGN directives,
+PCALIGN also changes the function alignment. If a function has one or more PCALIGN directives,
its address will be aligned to the same or coarser boundary, which is the maximum of all the
alignment values.
diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go
index 09f603a059..b046685ada 100644
--- a/src/cmd/internal/obj/arm64/obj7.go
+++ b/src/cmd/internal/obj/arm64/obj7.go
@@ -33,6 +33,7 @@ package arm64
import (
"cmd/internal/obj"
"cmd/internal/objabi"
+ "cmd/internal/src"
"cmd/internal/sys"
"math"
)
@@ -593,6 +594,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
p = c.stacksplit(p, c.autosize) // emit split check
}
+ var prologueEnd *obj.Prog
+
aoffset := c.autosize
if aoffset > 0xF0 {
aoffset = 0xF0
@@ -619,6 +622,8 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q.To.Type = obj.TYPE_REG
q.To.Reg = REGTMP
+ prologueEnd = q
+
q = obj.Appendp(q, c.newprog)
q.Pos = p.Pos
q.As = AMOVD
@@ -662,8 +667,12 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) {
q1.To.Offset = int64(-aoffset)
q1.To.Reg = REGSP
q1.Spadj = aoffset
+
+ prologueEnd = q1
}
+ prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd)
+
if objabi.Framepointer_enabled(objabi.GOOS, objabi.GOARCH) {
q1 = obj.Appendp(q1, c.newprog)
q1.Pos = p.Pos
diff --git a/src/cmd/internal/obj/data.go b/src/cmd/internal/obj/data.go
index 12385b59a0..f32e07acfe 100644
--- a/src/cmd/internal/obj/data.go
+++ b/src/cmd/internal/obj/data.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/ld.go b/src/cmd/internal/obj/ld.go
index 275540d795..4ba52c7785 100644
--- a/src/cmd/internal/obj/ld.go
+++ b/src/cmd/internal/obj/ld.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go
index 32906a3e05..f860b933d6 100644
--- a/src/cmd/internal/obj/link.go
+++ b/src/cmd/internal/obj/link.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go
index 6d7f42ed0b..93c313862e 100644
--- a/src/cmd/internal/obj/objfile.go
+++ b/src/cmd/internal/obj/objfile.go
@@ -788,6 +788,14 @@ func (ft *DwarfFixupTable) SetPrecursorFunc(s *LSym, fn interface{}) {
absfn.Type = objabi.SDWARFINFO
ft.ctxt.Data = append(ft.ctxt.Data, absfn)
+ // In the case of "late" inlining (inlines that happen during
+ // wrapper generation as opposed to the main inlining phase) it's
+ // possible that we didn't cache the abstract function sym for the
+ // text symbol -- do so now if needed. See issue 38068.
+ if s.Func != nil && s.Func.dwarfAbsFnSym == nil {
+ s.Func.dwarfAbsFnSym = absfn
+ }
+
ft.precursor[s] = fnState{precursor: fn, absfn: absfn}
}
diff --git a/src/cmd/internal/obj/objfile2.go b/src/cmd/internal/obj/objfile2.go
index 061e43c434..05400a11e6 100644
--- a/src/cmd/internal/obj/objfile2.go
+++ b/src/cmd/internal/obj/objfile2.go
@@ -159,6 +159,14 @@ func WriteObjFile2(ctxt *Link, b *bio.Writer, pkgpath string) {
}
}
+ // Blocks used only by tools (objdump, nm).
+
+ // Referenced symbol names from other packages
+ h.Offsets[goobj2.BlkRefName] = w.Offset()
+ w.refNames()
+
+ h.Offsets[goobj2.BlkEnd] = w.Offset()
+
// Fix up block offsets in the header
end := start + int64(w.Offset())
b.MustSeek(start, 0)
@@ -191,6 +199,9 @@ func (w *writer) StringTable() {
w.AddString(pkg)
}
w.ctxt.traverseSyms(traverseAll, func(s *LSym) {
+ // TODO: this includes references of indexed symbols from other packages,
+ // for which the linker doesn't need the name. Consider moving them to
+ // a separate block (for tools only).
if w.pkgpath != "" {
s.Name = strings.Replace(s.Name, "\"\".", w.pkgpath+".", -1)
}
@@ -316,6 +327,34 @@ func (w *writer) Aux(s *LSym) {
}
}
+// Emits names of referenced indexed symbols, used by tools (objdump, nm)
+// only.
+func (w *writer) refNames() {
+ seen := make(map[goobj2.SymRef]bool)
+ w.ctxt.traverseSyms(traverseRefs, func(rs *LSym) { // only traverse refs, not auxs, as tools don't need auxs
+ switch rs.PkgIdx {
+ case goobj2.PkgIdxNone, goobj2.PkgIdxBuiltin, goobj2.PkgIdxSelf: // not an external indexed reference
+ return
+ case goobj2.PkgIdxInvalid:
+ panic("unindexed symbol reference")
+ }
+ symref := makeSymRef(rs)
+ if seen[symref] {
+ return
+ }
+ seen[symref] = true
+ var o goobj2.RefName
+ o.SetSym(symref)
+ o.SetName(rs.Name, w.Writer)
+ o.Write(w.Writer)
+ })
+ // TODO: output in sorted order?
+ // Currently tools (cmd/internal/goobj package) doesn't use mmap,
+ // and it just read it into a map in memory upfront. If it uses
+ // mmap, if the output is sorted, it probably could avoid reading
+ // into memory and just do lookups in the mmap'd object file.
+}
+
// return the number of aux symbols s have.
func nAuxSym(s *LSym) int {
n := 0
diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go
index 0c401710f6..4f156d969b 100644
--- a/src/cmd/internal/obj/pass.go
+++ b/src/cmd/internal/obj/pass.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/pass.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/ppc64/doc.go b/src/cmd/internal/obj/ppc64/doc.go
index 2b6ef81b5b..6e601df82e 100644
--- a/src/cmd/internal/obj/ppc64/doc.go
+++ b/src/cmd/internal/obj/ppc64/doc.go
@@ -4,9 +4,7 @@
/*
Package ppc64 implements a PPC64 assembler that assembles Go asm into
-the corresponding PPC64 binary instructions as defined by the Power
-ISA. Since POWER8 is the minimum instruction set used by GOARCHes ppc64le
-and ppc64, refer to ISA 2.07B or later for details.
+the corresponding PPC64 instructions as defined by the Power ISA 3.0B.
This document provides information on how to write code in Go assembler
for PPC64, focusing on the differences between Go and PPC64 assembly language.
@@ -16,16 +14,24 @@ updates to the Go assembly language used mnemonics that are mostly similar if no
identical to the PPC64 mneumonics, such as VMX and VSX instructions. Not all detail
is included here; refer to the Power ISA document if interested in more detail.
+Starting with Go 1.15 the Go objdump supports the -gnu option, which provides a
+side by side view of the Go assembler and the PPC64 assembler output. This is
+extremely helpful in determining what final PPC64 assembly is generated from the
+corresponding Go assembly.
+
In the examples below, the Go assembly is on the left, PPC64 assembly on the right.
1. Operand ordering
In Go asm, the last operand (right) is the target operand, but with PPC64 asm,
- the first operand (left) is the target. In general, the remaining operands are
- in the same order except in a few special cases, especially those with 4 operands.
+ the first operand (left) is the target. The order of the remaining operands is
+ not consistent: in general opcodes with 3 operands that perform math or logical
+ operations have their operands in reverse order. Opcodes for vector instructions
+ and those with more than 3 operands usually have operands in the same order except
+ for the target operand, which is first in PPC64 asm and last in Go asm.
Example:
- ADD R3, R4, R5 <=> add r5, r3, r4
+ ADD R3, R4, R5 <=> add r5, r4, r3
2. Constant operands
@@ -179,6 +185,40 @@ In the examples below, the Go assembly is on the left, PPC64 assembly on the rig
Functions in Go are aligned to 16 bytes, as is the case in all other compilers
for PPC64.
+6. Shift instructions
+
+ The simple scalar shifts on PPC64 expect a shift count that fits in 5 bits for
+ 32-bit values or 6 bit for 64-bit values. If the shift count is a constant value
+ greater than the max then the assembler sets it to the max for that size (31 for
+ 32 bit values, 63 for 64 bit values). If the shift count is in a register, then
+ only the low 5 or 6 bits of the register will be used as the shift count. The
+ Go compiler will add appropriate code to compare the shift value to achieve the
+ the correct result, and the assembler does not add extra checking.
+
+ Examples:
+
+ SRAD $8,R3,R4 => sradi r4,r3,8
+ SRD $8,R3,R4 => rldicl r4,r3,56,8
+ SLD $8,R3,R4 => rldicr r4,r3,8,55
+ SRAW $16,R4,R5 => srawi r5,r4,16
+ SRW $40,R4,R5 => rlwinm r5,r4,0,0,31
+ SLW $12,R4,R5 => rlwinm r5,r4,12,0,19
+
+ Some non-simple shifts have operands in the Go assembly which don't map directly
+ onto operands in the PPC64 assembly. When an operand in a shift instruction in the
+ Go assembly is a bit mask, that mask is represented as a start and end bit in the
+ PPC64 assembly instead of a mask. See the ISA for more detail on these types of shifts.
+ Here are a few examples:
+
+ RLWMI $7,R3,$65535,R6 => rlwimi r6,r3,7,16,31
+ RLDMI $0,R4,$7,R6 => rldimi r6,r4,0,61
+
+ More recently, Go opcodes were added which map directly onto the PPC64 opcodes. It is
+ recommended to use the newer opcodes to avoid confusion.
+
+ RLDICL $0,R4,$15,R6 => rldicl r6,r4,0,15
+ RLDICR $0,R4,$15,R6 => rldicr r6.r4,0,15
+
Register naming
1. Special register usage in Go asm
diff --git a/src/cmd/internal/obj/sym.go b/src/cmd/internal/obj/sym.go
index 4a8b0ebb6f..400a7419bc 100644
--- a/src/cmd/internal/obj/sym.go
+++ b/src/cmd/internal/obj/sym.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/x86/a.out.go b/src/cmd/internal/obj/x86/a.out.go
index 517d541c2b..30c1a6a445 100644
--- a/src/cmd/internal/obj/x86/a.out.go
+++ b/src/cmd/internal/obj/x86/a.out.go
@@ -1,5 +1,5 @@
// Inferno utils/6c/6.out.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/6.out.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/6.out.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/x86/asm6.go b/src/cmd/internal/obj/x86/asm6.go
index f7d81dc2f7..82a2e6adc4 100644
--- a/src/cmd/internal/obj/x86/asm6.go
+++ b/src/cmd/internal/obj/x86/asm6.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/x86/list6.go b/src/cmd/internal/obj/x86/list6.go
index f194b4b075..60280312c9 100644
--- a/src/cmd/internal/obj/x86/list6.go
+++ b/src/cmd/internal/obj/x86/list6.go
@@ -1,5 +1,5 @@
// Inferno utils/6c/list.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6c/list.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6c/list.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/obj/x86/obj6.go b/src/cmd/internal/obj/x86/obj6.go
index 4283d995f9..c1e5bea055 100644
--- a/src/cmd/internal/obj/x86/obj6.go
+++ b/src/cmd/internal/obj/x86/obj6.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/pass.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/pass.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/pass.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/objabi/autotype.go b/src/cmd/internal/objabi/autotype.go
index 1b46b0ffec..f9d17a3b99 100644
--- a/src/cmd/internal/objabi/autotype.go
+++ b/src/cmd/internal/objabi/autotype.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/objabi/head.go b/src/cmd/internal/objabi/head.go
index 6836c338c9..95b8db3809 100644
--- a/src/cmd/internal/objabi/head.go
+++ b/src/cmd/internal/objabi/head.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/objabi/reloctype.go b/src/cmd/internal/objabi/reloctype.go
index dc6482802a..f029a3c396 100644
--- a/src/cmd/internal/objabi/reloctype.go
+++ b/src/cmd/internal/objabi/reloctype.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/objabi/symkind.go b/src/cmd/internal/objabi/symkind.go
index 69f15286cd..374aaa6514 100644
--- a/src/cmd/internal/objabi/symkind.go
+++ b/src/cmd/internal/objabi/symkind.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go
index 72dd5856f8..f7873a42b9 100644
--- a/src/cmd/internal/objabi/util.go
+++ b/src/cmd/internal/objabi/util.go
@@ -37,16 +37,13 @@ var (
const (
ElfRelocOffset = 256
- MachoRelocOffset = 2048 // reserve enough space for ELF relocations
+ MachoRelocOffset = 2048 // reserve enough space for ELF relocations
+ Go115AMD64 = "alignedjumps" // Should be "alignedjumps" or "normaljumps"; this replaces environment variable introduced in CL 219357.
)
+// TODO(1.16): assuming no issues in 1.15 release, remove this and related constant.
func goamd64() string {
- switch v := envOr("GOAMD64", defaultGOAMD64); v {
- case "normaljumps", "alignedjumps":
- return v
- }
- log.Fatalf("Invalid GOAMD64 value. Must be normaljumps or alignedjumps.")
- panic("unreachable")
+ return Go115AMD64
}
func goarm() int {
@@ -137,7 +134,7 @@ func init() {
}
func Framepointer_enabled(goos, goarch string) bool {
- return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && goos == "linux")
+ return framepointer_enabled != 0 && (goarch == "amd64" || goarch == "arm64" && (goos == "linux" || goos == "darwin"))
}
func addexp(s string) {
diff --git a/src/cmd/internal/test2json/test2json.go b/src/cmd/internal/test2json/test2json.go
index 098128ef3a..a01a8900e8 100644
--- a/src/cmd/internal/test2json/test2json.go
+++ b/src/cmd/internal/test2json/test2json.go
@@ -211,8 +211,18 @@ func (c *converter) handleInputLine(line []byte) {
}
}
+ // Not a special test output line.
if !ok {
- // Not a special test output line.
+ // Lookup the name of the test which produced the output using the
+ // indentation of the output as an index into the stack of the current
+ // subtests.
+ // If the indentation is greater than the number of current subtests
+ // then the output must have included extra indentation. We can't
+ // determine which subtest produced this output, so we default to the
+ // old behaviour of assuming the most recently run subtest produced it.
+ if indent > 0 && indent <= len(c.report) {
+ c.testName = c.report[indent-1].Test
+ }
c.output.write(origLine)
return
}
diff --git a/src/cmd/internal/test2json/testdata/issue29755.json b/src/cmd/internal/test2json/testdata/issue29755.json
new file mode 100644
index 0000000000..2e8ba48629
--- /dev/null
+++ b/src/cmd/internal/test2json/testdata/issue29755.json
@@ -0,0 +1,38 @@
+{"Action":"run","Test":"TestOutputWithSubtest"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"=== RUN TestOutputWithSubtest\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":"=== RUN TestOutputWithSubtest/sub_test\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test/sub2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test/sub2\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":"=== RUN TestOutputWithSubtest/sub_test2\n"}
+{"Action":"run","Test":"TestOutputWithSubtest/sub_test2/sub2"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":"=== RUN TestOutputWithSubtest/sub_test2/sub2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":"--- FAIL: TestOutputWithSubtest (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:6: output before sub tests\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:10: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:15: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" --- PASS: TestOutputWithSubtest/sub_test (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:9: output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:11: more output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test","Output":" foo_test.go:16: more output from sub test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test/sub2","Output":" foo_test.go:14: output from sub2 test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:22: output from root test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:27: output from root test\n"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test/sub2"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:21: output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:23: more output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2","Output":" foo_test.go:28: more output from sub test2\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":" --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)\n"}
+{"Action":"output","Test":"TestOutputWithSubtest/sub_test2/sub2","Output":" foo_test.go:26: output from sub2 test\n"}
+{"Action":"output","Test":"TestOutputWithSubtest","Output":" foo_test.go:32: output after sub test\n"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2/sub2"}
+{"Action":"pass","Test":"TestOutputWithSubtest/sub_test2"}
+{"Action":"fail","Test":"TestOutputWithSubtest"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"output","Output":"FAIL\tgotest.tools/gotestsum/foo\t0.001s\n"}
+{"Action":"output","Output":"FAIL\n"}
+{"Action":"fail"}
diff --git a/src/cmd/internal/test2json/testdata/issue29755.test b/src/cmd/internal/test2json/testdata/issue29755.test
new file mode 100644
index 0000000000..b0c596ce45
--- /dev/null
+++ b/src/cmd/internal/test2json/testdata/issue29755.test
@@ -0,0 +1,27 @@
+=== RUN TestOutputWithSubtest
+=== RUN TestOutputWithSubtest/sub_test
+=== RUN TestOutputWithSubtest/sub_test/sub2
+=== RUN TestOutputWithSubtest/sub_test2
+=== RUN TestOutputWithSubtest/sub_test2/sub2
+--- FAIL: TestOutputWithSubtest (0.00s)
+ foo_test.go:6: output before sub tests
+ foo_test.go:10: output from root test
+ foo_test.go:15: output from root test
+ --- PASS: TestOutputWithSubtest/sub_test (0.00s)
+ foo_test.go:9: output from sub test
+ foo_test.go:11: more output from sub test
+ foo_test.go:16: more output from sub test
+ --- PASS: TestOutputWithSubtest/sub_test/sub2 (0.00s)
+ foo_test.go:14: output from sub2 test
+ foo_test.go:22: output from root test
+ foo_test.go:27: output from root test
+ --- PASS: TestOutputWithSubtest/sub_test2 (0.00s)
+ foo_test.go:21: output from sub test2
+ foo_test.go:23: more output from sub test2
+ foo_test.go:28: more output from sub test2
+ --- PASS: TestOutputWithSubtest/sub_test2/sub2 (0.00s)
+ foo_test.go:26: output from sub2 test
+ foo_test.go:32: output after sub test
+FAIL
+FAIL gotest.tools/gotestsum/foo 0.001s
+FAIL
diff --git a/src/cmd/internal/test2json/testdata/smiley.json b/src/cmd/internal/test2json/testdata/smiley.json
index afa990d7c0..f49180d520 100644
--- a/src/cmd/internal/test2json/testdata/smiley.json
+++ b/src/cmd/internal/test2json/testdata/smiley.json
@@ -116,13 +116,13 @@
{"Action":"output","Test":"Test☺☹/2","Output":"=== CONT Test☺☹/2\n"}
{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":" \tvet_test.go:187: -tags=x testtag y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":" vet_test.go:187: -tags=x testtag y\n"}
{"Action":"pass","Test":"TestTags/x_testtag_y"}
{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":" \tvet_test.go:187: -tags=x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":" vet_test.go:187: -tags=x,testtag,y\n"}
{"Action":"pass","Test":"TestTags/x,testtag,y"}
{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":" \tvet_test.go:187: -tags=testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":" vet_test.go:187: -tags=testtag\n"}
{"Action":"pass","Test":"TestTags/testtag"}
{"Action":"pass","Test":"TestTags"}
{"Action":"cont","Test":"Test☺☹/1"}
@@ -139,28 +139,28 @@
{"Action":"output","Test":"Test☺☹Dirs/cgo","Output":"=== CONT Test☺☹Dirs/cgo\n"}
{"Action":"output","Test":"Test☺☹","Output":"--- PASS: Test☺☹ (0.39s)\n"}
{"Action":"output","Test":"Test☺☹/5","Output":" --- PASS: Test☺☹/5 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/5","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/5","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/5"}
{"Action":"output","Test":"Test☺☹/3","Output":" --- PASS: Test☺☹/3 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/3","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/3","Output":" vet_test.go:114: φιλεσ: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/3"}
{"Action":"output","Test":"Test☺☹/6","Output":" --- PASS: Test☺☹/6 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/6","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/6","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/6"}
{"Action":"output","Test":"Test☺☹/2","Output":" --- PASS: Test☺☹/2 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/2","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/2","Output":" vet_test.go:114: φιλεσ: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/2"}
{"Action":"output","Test":"Test☺☹/0","Output":" --- PASS: Test☺☹/0 (0.13s)\n"}
-{"Action":"output","Test":"Test☺☹/0","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/0","Output":" vet_test.go:114: φιλεσ: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/0"}
{"Action":"output","Test":"Test☺☹/4","Output":" --- PASS: Test☺☹/4 (0.16s)\n"}
-{"Action":"output","Test":"Test☺☹/4","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/4","Output":" vet_test.go:114: φιλεσ: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/4"}
{"Action":"output","Test":"Test☺☹/1","Output":" --- PASS: Test☺☹/1 (0.07s)\n"}
-{"Action":"output","Test":"Test☺☹/1","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/1","Output":" vet_test.go:114: φιλεσ: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/1"}
{"Action":"output","Test":"Test☺☹/7","Output":" --- PASS: Test☺☹/7 (0.19s)\n"}
-{"Action":"output","Test":"Test☺☹/7","Output":" \tvet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
+{"Action":"output","Test":"Test☺☹/7","Output":" vet_test.go:114: φιλεσ: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
{"Action":"pass","Test":"Test☺☹/7"}
{"Action":"pass","Test":"Test☺☹"}
{"Action":"output","Test":"Test☺☹Dirs","Output":"--- PASS: Test☺☹Dirs (0.01s)\n"}
diff --git a/src/cmd/internal/test2json/testdata/smiley.test b/src/cmd/internal/test2json/testdata/smiley.test
index 05edf5a312..bd1ed2dd9a 100644
--- a/src/cmd/internal/test2json/testdata/smiley.test
+++ b/src/cmd/internal/test2json/testdata/smiley.test
@@ -58,11 +58,11 @@
=== CONT Test☺☹/2
--- PASS: TestTags (0.00s)
--- PASS: TestTags/x_testtag_y (0.04s)
- vet_test.go:187: -tags=x testtag y
+ vet_test.go:187: -tags=x testtag y
--- PASS: TestTags/x,testtag,y (0.04s)
- vet_test.go:187: -tags=x,testtag,y
+ vet_test.go:187: -tags=x,testtag,y
--- PASS: TestTags/testtag (0.04s)
- vet_test.go:187: -tags=testtag
+ vet_test.go:187: -tags=testtag
=== CONT Test☺☹/1
=== CONT Test☺☹Dirs/testingpkg
=== CONT Test☺☹Dirs/buildtag
@@ -71,21 +71,21 @@
=== CONT Test☺☹Dirs/cgo
--- PASS: Test☺☹ (0.39s)
--- PASS: Test☺☹/5 (0.07s)
- vet_test.go:114: φιλεσ: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
+ vet_test.go:114: φιλεσ: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
--- PASS: Test☺☹/3 (0.07s)
- vet_test.go:114: φιλεσ: ["testdata/composite.go" "testdata/nilfunc.go"]
+ vet_test.go:114: φιλεσ: ["testdata/composite.go" "testdata/nilfunc.go"]
--- PASS: Test☺☹/6 (0.07s)
- vet_test.go:114: φιλεσ: ["testdata/copylock_range.go" "testdata/shadow.go"]
+ vet_test.go:114: φιλεσ: ["testdata/copylock_range.go" "testdata/shadow.go"]
--- PASS: Test☺☹/2 (0.07s)
- vet_test.go:114: φιλεσ: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
+ vet_test.go:114: φιλεσ: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
--- PASS: Test☺☹/0 (0.13s)
- vet_test.go:114: φιλεσ: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
+ vet_test.go:114: φιλεσ: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
--- PASS: Test☺☹/4 (0.16s)
- vet_test.go:114: φιλεσ: ["testdata/copylock.go" "testdata/print.go"]
+ vet_test.go:114: φιλεσ: ["testdata/copylock.go" "testdata/print.go"]
--- PASS: Test☺☹/1 (0.07s)
- vet_test.go:114: φιλεσ: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
+ vet_test.go:114: φιλεσ: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
--- PASS: Test☺☹/7 (0.19s)
- vet_test.go:114: φιλεσ: ["testdata/deadcode.go" "testdata/shift.go"]
+ vet_test.go:114: φιλεσ: ["testdata/deadcode.go" "testdata/shift.go"]
--- PASS: Test☺☹Dirs (0.01s)
--- PASS: Test☺☹Dirs/testingpkg (0.06s)
--- PASS: Test☺☹Dirs/divergent (0.05s)
diff --git a/src/cmd/internal/test2json/testdata/vet.json b/src/cmd/internal/test2json/testdata/vet.json
index 8c5921d686..2558d61e74 100644
--- a/src/cmd/internal/test2json/testdata/vet.json
+++ b/src/cmd/internal/test2json/testdata/vet.json
@@ -116,13 +116,13 @@
{"Action":"output","Test":"TestVet/2","Output":"=== CONT TestVet/2\n"}
{"Action":"output","Test":"TestTags","Output":"--- PASS: TestTags (0.00s)\n"}
{"Action":"output","Test":"TestTags/x_testtag_y","Output":" --- PASS: TestTags/x_testtag_y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x_testtag_y","Output":" \tvet_test.go:187: -tags=x testtag y\n"}
+{"Action":"output","Test":"TestTags/x_testtag_y","Output":" vet_test.go:187: -tags=x testtag y\n"}
{"Action":"pass","Test":"TestTags/x_testtag_y"}
{"Action":"output","Test":"TestTags/x,testtag,y","Output":" --- PASS: TestTags/x,testtag,y (0.04s)\n"}
-{"Action":"output","Test":"TestTags/x,testtag,y","Output":" \tvet_test.go:187: -tags=x,testtag,y\n"}
+{"Action":"output","Test":"TestTags/x,testtag,y","Output":" vet_test.go:187: -tags=x,testtag,y\n"}
{"Action":"pass","Test":"TestTags/x,testtag,y"}
{"Action":"output","Test":"TestTags/testtag","Output":" --- PASS: TestTags/testtag (0.04s)\n"}
-{"Action":"output","Test":"TestTags/testtag","Output":" \tvet_test.go:187: -tags=testtag\n"}
+{"Action":"output","Test":"TestTags/testtag","Output":" vet_test.go:187: -tags=testtag\n"}
{"Action":"pass","Test":"TestTags/testtag"}
{"Action":"pass","Test":"TestTags"}
{"Action":"cont","Test":"TestVet/1"}
@@ -139,28 +139,28 @@
{"Action":"output","Test":"TestVetDirs/cgo","Output":"=== CONT TestVetDirs/cgo\n"}
{"Action":"output","Test":"TestVet","Output":"--- PASS: TestVet (0.39s)\n"}
{"Action":"output","Test":"TestVet/5","Output":" --- PASS: TestVet/5 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/5","Output":" \tvet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
+{"Action":"output","Test":"TestVet/5","Output":" vet_test.go:114: files: [\"testdata/copylock_func.go\" \"testdata/rangeloop.go\"]\n"}
{"Action":"pass","Test":"TestVet/5"}
{"Action":"output","Test":"TestVet/3","Output":" --- PASS: TestVet/3 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/3","Output":" \tvet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
+{"Action":"output","Test":"TestVet/3","Output":" vet_test.go:114: files: [\"testdata/composite.go\" \"testdata/nilfunc.go\"]\n"}
{"Action":"pass","Test":"TestVet/3"}
{"Action":"output","Test":"TestVet/6","Output":" --- PASS: TestVet/6 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/6","Output":" \tvet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
+{"Action":"output","Test":"TestVet/6","Output":" vet_test.go:114: files: [\"testdata/copylock_range.go\" \"testdata/shadow.go\"]\n"}
{"Action":"pass","Test":"TestVet/6"}
{"Action":"output","Test":"TestVet/2","Output":" --- PASS: TestVet/2 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/2","Output":" \tvet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
+{"Action":"output","Test":"TestVet/2","Output":" vet_test.go:114: files: [\"testdata/bool.go\" \"testdata/method.go\" \"testdata/unused.go\"]\n"}
{"Action":"pass","Test":"TestVet/2"}
{"Action":"output","Test":"TestVet/0","Output":" --- PASS: TestVet/0 (0.13s)\n"}
-{"Action":"output","Test":"TestVet/0","Output":" \tvet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
+{"Action":"output","Test":"TestVet/0","Output":" vet_test.go:114: files: [\"testdata/assign.go\" \"testdata/httpresponse.go\" \"testdata/structtag.go\"]\n"}
{"Action":"pass","Test":"TestVet/0"}
{"Action":"output","Test":"TestVet/4","Output":" --- PASS: TestVet/4 (0.16s)\n"}
-{"Action":"output","Test":"TestVet/4","Output":" \tvet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
+{"Action":"output","Test":"TestVet/4","Output":" vet_test.go:114: files: [\"testdata/copylock.go\" \"testdata/print.go\"]\n"}
{"Action":"pass","Test":"TestVet/4"}
{"Action":"output","Test":"TestVet/1","Output":" --- PASS: TestVet/1 (0.07s)\n"}
-{"Action":"output","Test":"TestVet/1","Output":" \tvet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
+{"Action":"output","Test":"TestVet/1","Output":" vet_test.go:114: files: [\"testdata/atomic.go\" \"testdata/lostcancel.go\" \"testdata/unsafeptr.go\"]\n"}
{"Action":"pass","Test":"TestVet/1"}
{"Action":"output","Test":"TestVet/7","Output":" --- PASS: TestVet/7 (0.19s)\n"}
-{"Action":"output","Test":"TestVet/7","Output":" \tvet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
+{"Action":"output","Test":"TestVet/7","Output":" vet_test.go:114: files: [\"testdata/deadcode.go\" \"testdata/shift.go\"]\n"}
{"Action":"pass","Test":"TestVet/7"}
{"Action":"pass","Test":"TestVet"}
{"Action":"output","Test":"TestVetDirs","Output":"--- PASS: TestVetDirs (0.01s)\n"}
diff --git a/src/cmd/internal/test2json/testdata/vet.test b/src/cmd/internal/test2json/testdata/vet.test
index 3389559cb8..59d187e0a3 100644
--- a/src/cmd/internal/test2json/testdata/vet.test
+++ b/src/cmd/internal/test2json/testdata/vet.test
@@ -58,11 +58,11 @@
=== CONT TestVet/2
--- PASS: TestTags (0.00s)
--- PASS: TestTags/x_testtag_y (0.04s)
- vet_test.go:187: -tags=x testtag y
+ vet_test.go:187: -tags=x testtag y
--- PASS: TestTags/x,testtag,y (0.04s)
- vet_test.go:187: -tags=x,testtag,y
+ vet_test.go:187: -tags=x,testtag,y
--- PASS: TestTags/testtag (0.04s)
- vet_test.go:187: -tags=testtag
+ vet_test.go:187: -tags=testtag
=== CONT TestVet/1
=== CONT TestVetDirs/testingpkg
=== CONT TestVetDirs/buildtag
@@ -71,21 +71,21 @@
=== CONT TestVetDirs/cgo
--- PASS: TestVet (0.39s)
--- PASS: TestVet/5 (0.07s)
- vet_test.go:114: files: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
+ vet_test.go:114: files: ["testdata/copylock_func.go" "testdata/rangeloop.go"]
--- PASS: TestVet/3 (0.07s)
- vet_test.go:114: files: ["testdata/composite.go" "testdata/nilfunc.go"]
+ vet_test.go:114: files: ["testdata/composite.go" "testdata/nilfunc.go"]
--- PASS: TestVet/6 (0.07s)
- vet_test.go:114: files: ["testdata/copylock_range.go" "testdata/shadow.go"]
+ vet_test.go:114: files: ["testdata/copylock_range.go" "testdata/shadow.go"]
--- PASS: TestVet/2 (0.07s)
- vet_test.go:114: files: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
+ vet_test.go:114: files: ["testdata/bool.go" "testdata/method.go" "testdata/unused.go"]
--- PASS: TestVet/0 (0.13s)
- vet_test.go:114: files: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
+ vet_test.go:114: files: ["testdata/assign.go" "testdata/httpresponse.go" "testdata/structtag.go"]
--- PASS: TestVet/4 (0.16s)
- vet_test.go:114: files: ["testdata/copylock.go" "testdata/print.go"]
+ vet_test.go:114: files: ["testdata/copylock.go" "testdata/print.go"]
--- PASS: TestVet/1 (0.07s)
- vet_test.go:114: files: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
+ vet_test.go:114: files: ["testdata/atomic.go" "testdata/lostcancel.go" "testdata/unsafeptr.go"]
--- PASS: TestVet/7 (0.19s)
- vet_test.go:114: files: ["testdata/deadcode.go" "testdata/shift.go"]
+ vet_test.go:114: files: ["testdata/deadcode.go" "testdata/shift.go"]
--- PASS: TestVetDirs (0.01s)
--- PASS: TestVetDirs/testingpkg (0.06s)
--- PASS: TestVetDirs/divergent (0.05s)
diff --git a/src/cmd/link/dwarf_test.go b/src/cmd/link/dwarf_test.go
index 5926f09e4a..a9f58db230 100644
--- a/src/cmd/link/dwarf_test.go
+++ b/src/cmd/link/dwarf_test.go
@@ -33,8 +33,8 @@ func testDWARF(t *testing.T, buildmode string, expectDWARF bool, env ...string)
t.Fatalf("go list: %v\n%s", err, out)
}
if string(out) != "false\n" {
- if os.Getenv("GOROOT_FINAL_OLD") != "" {
- t.Skip("cmd/link is stale, but $GOROOT_FINAL_OLD is set")
+ if strings.HasPrefix(testenv.Builder(), "darwin-") {
+ t.Skipf("cmd/link is spuriously stale on Darwin builders - see #33598")
}
t.Fatalf("cmd/link is stale - run go install cmd/link")
}
diff --git a/src/cmd/link/internal/amd64/asm.go b/src/cmd/link/internal/amd64/asm.go
index c2d54703c1..b8dc0fce6f 100644
--- a/src/cmd/link/internal/amd64/asm.go
+++ b/src/cmd/link/internal/amd64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/amd64/l.go b/src/cmd/link/internal/amd64/l.go
index 393da6bf28..a9afb3a39f 100644
--- a/src/cmd/link/internal/amd64/l.go
+++ b/src/cmd/link/internal/amd64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/amd64/obj.go b/src/cmd/link/internal/amd64/obj.go
index 1fa8cbb4d0..705827d6be 100644
--- a/src/cmd/link/internal/amd64/obj.go
+++ b/src/cmd/link/internal/amd64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/arm/asm.go b/src/cmd/link/internal/arm/asm.go
index a2024bcede..903e62108e 100644
--- a/src/cmd/link/internal/arm/asm.go
+++ b/src/cmd/link/internal/arm/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -383,12 +383,16 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
offset := (signext24(r.Add()&0xffffff) + 2) * 4
var tramp loader.Sym
for i := 0; ; i++ {
- name := ldr.SymName(rs) + fmt.Sprintf("%+d-tramp%d", offset, i)
+ oName := ldr.SymName(rs)
+ name := oName + fmt.Sprintf("%+d-tramp%d", offset, i)
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
if ldr.SymType(tramp) == sym.SDYNIMPORT {
// don't reuse trampoline defined in other module
continue
}
+ if oName == "runtime.deferreturn" {
+ ldr.SetIsDeferReturnTramp(tramp, true)
+ }
if ldr.SymValue(tramp) == 0 {
// either the trampoline does not exist -- we need to create one,
// or found one the address which is not assigned -- this will be
diff --git a/src/cmd/link/internal/arm/l.go b/src/cmd/link/internal/arm/l.go
index a83d26bf06..d16dc2726e 100644
--- a/src/cmd/link/internal/arm/l.go
+++ b/src/cmd/link/internal/arm/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -33,7 +33,7 @@ package arm
// Writing object files.
// Inferno utils/5l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/arm/obj.go b/src/cmd/link/internal/arm/obj.go
index 653f16dba1..47bc053c7a 100644
--- a/src/cmd/link/internal/arm/obj.go
+++ b/src/cmd/link/internal/arm/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go
index dc3e45d6c0..417e4b1f4c 100644
--- a/src/cmd/link/internal/arm64/asm.go
+++ b/src/cmd/link/internal/arm64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/arm64/l.go b/src/cmd/link/internal/arm64/l.go
index 5f3530335e..4aa2708df6 100644
--- a/src/cmd/link/internal/arm64/l.go
+++ b/src/cmd/link/internal/arm64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/arm64/obj.go b/src/cmd/link/internal/arm64/obj.go
index ffce0cb17d..20426c5c69 100644
--- a/src/cmd/link/internal/arm64/obj.go
+++ b/src/cmd/link/internal/arm64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/ar.go b/src/cmd/link/internal/ld/ar.go
index 268f40e92d..52adbc3bab 100644
--- a/src/cmd/link/internal/ld/ar.go
+++ b/src/cmd/link/internal/ld/ar.go
@@ -1,5 +1,5 @@
// Inferno utils/include/ar.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/include/ar.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go
index 162ef9ba4e..d3f308c8fa 100644
--- a/src/cmd/link/internal/ld/data.go
+++ b/src/cmd/link/internal/ld/data.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -1730,7 +1730,7 @@ func (state *dodataState) allocateDataSections2(ctxt *Link) {
ldr.SetSymSect(ldr.LookupOrCreateSym("runtime.end", 0), sect)
// Coverage instrumentation counters for libfuzzer.
- if len(state.data[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
+ if len(state.data2[sym.SLIBFUZZER_EXTRA_COUNTER]) > 0 {
state.allocateNamedSectionAndAssignSyms2(&Segdata, "__libfuzzer_extra_counters", sym.SLIBFUZZER_EXTRA_COUNTER, sym.Sxxx, 06)
}
@@ -2177,7 +2177,7 @@ func (ctxt *Link) textaddress() {
// merge tramps into Textp, keeping Textp in address order
if ntramps != 0 {
- newtextp := make([]loader.Sym, 0, len(ctxt.Textp)+ntramps)
+ newtextp := make([]loader.Sym, 0, len(ctxt.Textp2)+ntramps)
i := 0
for _, s := range ctxt.Textp2 {
for ; i < ntramps && ldr.SymValue(ctxt.tramps[i]) < ldr.SymValue(s); i++ {
diff --git a/src/cmd/link/internal/ld/decodesym.go b/src/cmd/link/internal/ld/decodesym.go
index e9c87efe37..21bcc3a726 100644
--- a/src/cmd/link/internal/ld/decodesym.go
+++ b/src/cmd/link/internal/ld/decodesym.go
@@ -10,6 +10,7 @@ import (
"cmd/link/internal/loader"
"cmd/link/internal/sym"
"debug/elf"
+ "log"
)
// Decoding the type.* symbols. This has to be in sync with
@@ -229,8 +230,15 @@ func decodetypeGcmask(ctxt *Link, s loader.Sym) []byte {
ptrdata := decodetypePtrdata(ctxt.Arch, symData)
sect := findShlibSection(ctxt, ctxt.loader.SymPkg(s), addr)
if sect != nil {
- r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
- sect.ReadAt(r, int64(addr-sect.Addr))
+ bits := ptrdata / int64(ctxt.Arch.PtrSize)
+ r := make([]byte, (bits+7)/8)
+ // ldshlibsyms avoids closing the ELF file so sect.ReadAt works.
+ // If we remove this read (and the ones in decodetypeGcprog), we
+ // can close the file.
+ _, err := sect.ReadAt(r, int64(addr-sect.Addr))
+ if err != nil {
+ log.Fatal(err)
+ }
return r
}
Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
@@ -251,9 +259,15 @@ func decodetypeGcprog(ctxt *Link, s loader.Sym) []byte {
// A gcprog is a 4-byte uint32 indicating length, followed by
// the actual program.
progsize := make([]byte, 4)
- sect.ReadAt(progsize, int64(addr-sect.Addr))
+ _, err := sect.ReadAt(progsize, int64(addr-sect.Addr))
+ if err != nil {
+ log.Fatal(err)
+ }
progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
- sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+ _, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+ if err != nil {
+ log.Fatal(err)
+ }
return append(progsize, progbytes...)
}
Exitf("cannot find gcmask for %s", ctxt.loader.SymName(s))
@@ -268,7 +282,7 @@ func decodetypeGcprog(ctxt *Link, s loader.Sym) []byte {
func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
for _, shlib := range ctxt.Shlibs {
if shlib.Path == path {
- for _, sect := range shlib.File.Sections {
+ for _, sect := range shlib.File.Sections[1:] { // skip the NULL section
if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
return sect
}
@@ -279,8 +293,5 @@ func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
}
func decodetypeGcprogShlib(ctxt *Link, data []byte) uint64 {
- if ctxt.Arch.Family == sys.ARM64 {
- return 0
- }
return decodeInuxi(ctxt.Arch, data[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go
index 95e6b12282..8df03d74f1 100644
--- a/src/cmd/link/internal/ld/dwarf.go
+++ b/src/cmd/link/internal/ld/dwarf.go
@@ -1264,6 +1264,18 @@ func (d *dwctxt2) writelines(unit *sym.CompilationUnit, ls loader.Sym) {
}
}
+ // Issue 38192: the DWARF standard specifies that when you issue
+ // an end-sequence op, the PC value should be one past the last
+ // text address in the translation unit, so apply a delta to the
+ // text address before the end sequence op. If this isn't done,
+ // GDB will assign a line number of zero the last row in the line
+ // table, which we don't want. The 1 + ptrsize amount is somewhat
+ // arbitrary, this is chosen to be consistent with the way LLVM
+ // emits its end sequence ops.
+ lsu.AddUint8(dwarf.DW_LNS_advance_pc)
+ dwarf.Uleb128put(d, lsDwsym, int64(1+d.arch.PtrSize))
+
+ // Emit an end-sequence at the end of the unit.
lsu.AddUint8(0) // start extended opcode
dwarf.Uleb128put(d, lsDwsym, 1)
lsu.AddUint8(dwarf.DW_LNE_end_sequence)
diff --git a/src/cmd/link/internal/ld/dwarf_test.go b/src/cmd/link/internal/ld/dwarf_test.go
index a1c8496eea..fb9c45b07d 100644
--- a/src/cmd/link/internal/ld/dwarf_test.go
+++ b/src/cmd/link/internal/ld/dwarf_test.go
@@ -1368,3 +1368,114 @@ func main() {
rdr.SkipChildren()
}
}
+
+func TestIssue38192(t *testing.T) {
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOOS == "plan9" {
+ t.Skip("skipping on plan9; no DWARF symbol table in executables")
+ }
+
+ // Build a test program that contains a translation unit whose
+ // text (from am assembly source) contains only a single instruction.
+ tmpdir, err := ioutil.TempDir("", "TestIssue38192")
+ if err != nil {
+ t.Fatalf("could not create directory: %v", err)
+ }
+ defer os.RemoveAll(tmpdir)
+ wd, err := os.Getwd()
+ if err != nil {
+ t.Fatalf("where am I? %v", err)
+ }
+ pdir := filepath.Join(wd, "testdata", "issue38192")
+ f := gobuildTestdata(t, tmpdir, pdir, DefaultOpt)
+
+ // Open the resulting binary and examine the DWARF it contains.
+ // Look for the function of interest ("main.singleInstruction")
+ // and verify that the line table has an entry not just for the
+ // single instruction but also a dummy instruction following it,
+ // so as to test that whoever is emitting the DWARF doesn't
+ // emit an end-sequence op immediately after the last instruction
+ // in the translation unit.
+ //
+ // NB: another way to write this test would have been to run the
+ // resulting executable under GDB, set a breakpoint in
+ // "main.singleInstruction", then verify that GDB displays the
+ // correct line/file information. Given the headache and flakiness
+ // associated with GDB-based tests these days, a direct read of
+ // the line table seems more desirable.
+ rows := []dwarf.LineEntry{}
+ dw, err := f.DWARF()
+ if err != nil {
+ t.Fatalf("error parsing DWARF: %v", err)
+ }
+ rdr := dw.Reader()
+ for {
+ e, err := rdr.Next()
+ if err != nil {
+ t.Fatalf("error reading DWARF: %v", err)
+ }
+ if e == nil {
+ break
+ }
+ if e.Tag != dwarf.TagCompileUnit {
+ continue
+ }
+ // NB: there can be multiple compile units named "main".
+ name := e.Val(dwarf.AttrName).(string)
+ if name != "main" {
+ continue
+ }
+ lnrdr, err := dw.LineReader(e)
+ if err != nil {
+ t.Fatalf("error creating DWARF line reader: %v", err)
+ }
+ if lnrdr != nil {
+ var lne dwarf.LineEntry
+ for {
+ err := lnrdr.Next(&lne)
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ t.Fatalf("error reading next DWARF line: %v", err)
+ }
+ if !strings.HasSuffix(lne.File.Name, "ld/testdata/issue38192/oneline.s") {
+ continue
+ }
+ rows = append(rows, lne)
+ }
+ }
+ rdr.SkipChildren()
+ }
+ f.Close()
+
+ // Make sure that:
+ // - main.singleInstruction appears in the line table
+ // - more than one PC value appears the line table for
+ // that compilation unit.
+ // - at least one row has the correct line number (8)
+ pcs := make(map[uint64]bool)
+ line8seen := false
+ for _, r := range rows {
+ pcs[r.Address] = true
+ if r.Line == 8 {
+ line8seen = true
+ }
+ }
+ failed := false
+ if len(pcs) < 2 {
+ failed = true
+ t.Errorf("not enough line table rows for main.singleInstruction (got %d, wanted > 1", len(pcs))
+ }
+ if !line8seen {
+ failed = true
+ t.Errorf("line table does not contain correct line for main.singleInstruction")
+ }
+ if !failed {
+ return
+ }
+ for i, r := range rows {
+ t.Logf("row %d: A=%x F=%s L=%d\n", i, r.Address, r.File.Name, r.Line)
+ }
+}
diff --git a/src/cmd/link/internal/ld/fallocate_test.go b/src/cmd/link/internal/ld/fallocate_test.go
new file mode 100644
index 0000000000..51f5fcdd9f
--- /dev/null
+++ b/src/cmd/link/internal/ld/fallocate_test.go
@@ -0,0 +1,65 @@
+// Copyright 2020 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 linux
+
+package ld
+
+import (
+ "io/ioutil"
+ "os"
+ "path/filepath"
+ "syscall"
+ "testing"
+)
+
+func TestFallocate(t *testing.T) {
+ dir, err := ioutil.TempDir("", "TestFallocate")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+ filename := filepath.Join(dir, "a.out")
+ out := NewOutBuf(nil)
+ err = out.Open(filename)
+ if err != nil {
+ t.Fatalf("Open file failed: %v", err)
+ }
+ defer out.Close()
+
+ // Try fallocate first.
+ for {
+ err = out.fallocate(1 << 10)
+ if err == syscall.EOPNOTSUPP { // The underlying file system may not support fallocate
+ t.Skip("fallocate is not supported")
+ }
+ if err == syscall.EINTR {
+ continue // try again
+ }
+ if err != nil {
+ t.Fatalf("fallocate failed: %v", err)
+ }
+ break
+ }
+
+ // Mmap 1 MiB initially, and grow to 2 and 3 MiB.
+ // Check if the file size and disk usage is expected.
+ for _, sz := range []int64{1 << 20, 2 << 20, 3 << 20} {
+ err = out.Mmap(uint64(sz))
+ if err != nil {
+ t.Fatalf("Mmap failed: %v", err)
+ }
+ stat, err := os.Stat(filename)
+ if err != nil {
+ t.Fatalf("Stat failed: %v", err)
+ }
+ if got := stat.Size(); got != sz {
+ t.Errorf("unexpected file size: got %d, want %d", got, sz)
+ }
+ if got, want := stat.Sys().(*syscall.Stat_t).Blocks, (sz+511)/512; got != want {
+ t.Errorf("unexpected disk usage: got %d blocks, want %d", got, want)
+ }
+ out.munmap()
+ }
+}
diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go
index c913a519a1..e56a6690fb 100644
--- a/src/cmd/link/internal/ld/ld.go
+++ b/src/cmd/link/internal/ld/ld.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -160,7 +160,12 @@ func addlib(ctxt *Link, src, obj, lib string, fingerprint goobj2.FingerprintType
pkg := pkgname(ctxt, lib)
// already loaded?
- if l := ctxt.LibraryByPkg[pkg]; l != nil {
+ if l := ctxt.LibraryByPkg[pkg]; l != nil && !l.Fingerprint.IsZero() {
+ // Normally, packages are loaded in dependency order, and if l != nil
+ // l is already loaded with the actual fingerprint. In shared build mode,
+ // however, packages may be added not in dependency order, and it is
+ // possible that l's fingerprint is not yet loaded -- exclude it in
+ // checking.
checkFingerprint(l, l.Fingerprint, src, fingerprint)
return l
}
diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go
index b2d74ed4e6..b1bfd6e96b 100644
--- a/src/cmd/link/internal/ld/lib.go
+++ b/src/cmd/link/internal/ld/lib.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -65,7 +65,7 @@ import (
// Data layout and relocation.
// Derived from Inferno utils/6l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -157,6 +157,7 @@ const AfterLoadlibFull = 2
func (ctxt *Link) mkArchSym(which int, name string, ver int, ls *loader.Sym, ss **sym.Symbol) {
if which == BeforeLoadlibFull {
*ls = ctxt.loader.LookupOrCreateSym(name, ver)
+ ctxt.loader.SetAttrReachable(*ls, true)
} else {
*ss = ctxt.loader.Syms[*ls]
}
@@ -167,6 +168,7 @@ func (ctxt *Link) mkArchSym(which int, name string, ver int, ls *loader.Sym, ss
func (ctxt *Link) mkArchSymVec(which int, name string, ver int, ls []loader.Sym, ss []*sym.Symbol) {
if which == BeforeLoadlibFull {
ls[ver] = ctxt.loader.LookupOrCreateSym(name, ver)
+ ctxt.loader.SetAttrReachable(ls[ver], true)
} else if ls[ver] != 0 {
ss[ver] = ctxt.loader.Syms[ls[ver]]
}
@@ -1467,6 +1469,7 @@ func (ctxt *Link) hostlink() {
}
}
+ var altLinker string
if ctxt.IsELF && ctxt.DynlinkingGo() {
// We force all symbol resolution to be done at program startup
// because lazy PLT resolution can use large amounts of stack at
@@ -1478,6 +1481,11 @@ func (ctxt *Link) hostlink() {
// from the beginning of the section (like sym.STYPE).
argv = append(argv, "-Wl,-znocopyreloc")
+ if objabi.GOOS == "android" {
+ // Use lld to avoid errors from default linker (issue #38838)
+ altLinker = "lld"
+ }
+
if ctxt.Arch.InFamily(sys.ARM, sys.ARM64) && objabi.GOOS == "linux" {
// On ARM, the GNU linker will generate COPY relocations
// even with -znocopyreloc set.
@@ -1487,7 +1495,7 @@ func (ctxt *Link) hostlink() {
// generating COPY relocations.
//
// In both cases, switch to gold.
- argv = append(argv, "-fuse-ld=gold")
+ altLinker = "gold"
// If gold is not installed, gcc will silently switch
// back to ld.bfd. So we parse the version information
@@ -1500,10 +1508,9 @@ func (ctxt *Link) hostlink() {
}
}
}
-
if ctxt.Arch.Family == sys.ARM64 && objabi.GOOS == "freebsd" {
// Switch to ld.bfd on freebsd/arm64.
- argv = append(argv, "-fuse-ld=bfd")
+ altLinker = "bfd"
// Provide a useful error if ld.bfd is missing.
cmd := exec.Command(*flagExtld, "-fuse-ld=bfd", "-Wl,--version")
@@ -1513,6 +1520,9 @@ func (ctxt *Link) hostlink() {
}
}
}
+ if altLinker != "" {
+ argv = append(argv, "-fuse-ld="+altLinker)
+ }
if ctxt.IsELF && len(buildinfo) > 0 {
argv = append(argv, fmt.Sprintf("-Wl,--build-id=0x%x", buildinfo))
@@ -1549,7 +1559,7 @@ func (ctxt *Link) hostlink() {
}
const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu"
- if ctxt.compressDWARF && linkerFlagSupported(argv[0], compressDWARF) {
+ if ctxt.compressDWARF && linkerFlagSupported(argv[0], altLinker, compressDWARF) {
argv = append(argv, compressDWARF)
}
@@ -1639,7 +1649,7 @@ func (ctxt *Link) hostlink() {
if ctxt.BuildMode == BuildModeExe && !ctxt.linkShared {
// GCC uses -no-pie, clang uses -nopie.
for _, nopie := range []string{"-no-pie", "-nopie"} {
- if linkerFlagSupported(argv[0], nopie) {
+ if linkerFlagSupported(argv[0], altLinker, nopie) {
argv = append(argv, nopie)
break
}
@@ -1740,7 +1750,7 @@ func (ctxt *Link) hostlink() {
var createTrivialCOnce sync.Once
-func linkerFlagSupported(linker, flag string) bool {
+func linkerFlagSupported(linker, altLinker, 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 {
@@ -1800,6 +1810,9 @@ func linkerFlagSupported(linker, flag string) bool {
}
}
+ if altLinker != "" {
+ flags = append(flags, "-fuse-ld="+altLinker)
+ }
flags = append(flags, flag, "trivial.c")
cmd := exec.Command(linker, flags...)
@@ -2114,7 +2127,9 @@ func ldshlibsyms(ctxt *Link, shlib string) {
Errorf(nil, "cannot open shared library: %s", libpath)
return
}
- defer f.Close()
+ // Keep the file open as decodetypeGcprog needs to read from it.
+ // TODO: fix. Maybe mmap the file.
+ //defer f.Close()
hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
if err != nil {
diff --git a/src/cmd/link/internal/ld/link.go b/src/cmd/link/internal/ld/link.go
index 84b1f9121e..435b6087ea 100644
--- a/src/cmd/link/internal/ld/link.go
+++ b/src/cmd/link/internal/ld/link.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/macho.go b/src/cmd/link/internal/ld/macho.go
index 4dc7f819eb..5548b8c666 100644
--- a/src/cmd/link/internal/ld/macho.go
+++ b/src/cmd/link/internal/ld/macho.go
@@ -798,7 +798,7 @@ func collectmachosyms(ctxt *Link) {
continue
}
t := ldr.SymType(s)
- if t >= sym.SELFRXSECT && t < sym.SXREF { // data sections handled in dodata
+ if t >= sym.SELFRXSECT && t < sym.SXREF || t == sym.SCONST { // data sections handled in dodata
if t == sym.STLSBSS {
// TLSBSS is not used on darwin. See data.go:allocateDataSections
continue
@@ -810,7 +810,7 @@ func collectmachosyms(ctxt *Link) {
}
switch t {
- case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT, sym.SCONST:
+ case sym.SDYNIMPORT, sym.SHOSTOBJ, sym.SUNDEFEXT:
addsym(s)
}
diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go
index 1ed8ccb828..2738c8a6e4 100644
--- a/src/cmd/link/internal/ld/main.go
+++ b/src/cmd/link/internal/ld/main.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/outbuf.go b/src/cmd/link/internal/ld/outbuf.go
index 4ce211172c..09162ae90f 100644
--- a/src/cmd/link/internal/ld/outbuf.go
+++ b/src/cmd/link/internal/ld/outbuf.go
@@ -115,7 +115,6 @@ func (out *OutBuf) Close() error {
if out.isMmapped() {
out.copyHeap()
out.munmap()
- return nil
}
if out.f == nil {
return nil
diff --git a/src/cmd/link/internal/ld/outbuf_darwin.go b/src/cmd/link/internal/ld/outbuf_darwin.go
index 299902ec62..d7e3372230 100644
--- a/src/cmd/link/internal/ld/outbuf_darwin.go
+++ b/src/cmd/link/internal/ld/outbuf_darwin.go
@@ -10,16 +10,28 @@ import (
)
func (out *OutBuf) fallocate(size uint64) error {
+ stat, err := out.f.Stat()
+ if err != nil {
+ return err
+ }
+ // F_PEOFPOSMODE allocates from the end of the file, so we want the size difference.
+ // Apparently, it uses the end of the allocation, instead of the logical end of the
+ // the file.
+ cursize := uint64(stat.Sys().(*syscall.Stat_t).Blocks * 512) // allocated size
+ if size <= cursize {
+ return nil
+ }
+
store := &syscall.Fstore_t{
Flags: syscall.F_ALLOCATEALL,
Posmode: syscall.F_PEOFPOSMODE,
Offset: 0,
- Length: int64(size),
+ Length: int64(size - cursize),
}
- _, _, err := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
- if err != 0 {
- return err
+ _, _, errno := syscall.Syscall(syscall.SYS_FCNTL, uintptr(out.f.Fd()), syscall.F_PREALLOCATE, uintptr(unsafe.Pointer(store)))
+ if errno != 0 {
+ return errno
}
return nil
diff --git a/src/cmd/link/internal/ld/outbuf_linux.go b/src/cmd/link/internal/ld/outbuf_linux.go
index 93e621a70f..bd9a0c6761 100644
--- a/src/cmd/link/internal/ld/outbuf_linux.go
+++ b/src/cmd/link/internal/ld/outbuf_linux.go
@@ -7,5 +7,5 @@ package ld
import "syscall"
func (out *OutBuf) fallocate(size uint64) error {
- return syscall.Fallocate(int(out.f.Fd()), outbufMode, 0, int64(size))
+ return syscall.Fallocate(int(out.f.Fd()), 0, 0, int64(size))
}
diff --git a/src/cmd/link/internal/ld/outbuf_mmap.go b/src/cmd/link/internal/ld/outbuf_mmap.go
index e6ee041abb..e2e50cc84f 100644
--- a/src/cmd/link/internal/ld/outbuf_mmap.go
+++ b/src/cmd/link/internal/ld/outbuf_mmap.go
@@ -10,8 +10,12 @@ import (
"syscall"
)
-func (out *OutBuf) Mmap(filesize uint64) error {
- err := out.fallocate(filesize)
+func (out *OutBuf) Mmap(filesize uint64) (err error) {
+ for {
+ if err = out.fallocate(filesize); err != syscall.EINTR {
+ break
+ }
+ }
if err != nil {
// Some file systems do not support fallocate. We ignore that error as linking
// can still take place, but you might SIGBUS when you write to the mmapped
diff --git a/src/cmd/link/internal/ld/outbuf_windows.go b/src/cmd/link/internal/ld/outbuf_windows.go
index a7140cce38..807c0e227d 100644
--- a/src/cmd/link/internal/ld/outbuf_windows.go
+++ b/src/cmd/link/internal/ld/outbuf_windows.go
@@ -35,7 +35,13 @@ func (out *OutBuf) munmap() {
if out.buf == nil {
return
}
- err := syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])))
+ // Apparently unmapping without flush may cause ACCESS_DENIED error
+ // (see issue 38440).
+ err := syscall.FlushViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])), 0)
+ if err != nil {
+ Exitf("FlushViewOfFile failed: %v", err)
+ }
+ err = syscall.UnmapViewOfFile(uintptr(unsafe.Pointer(&out.buf[0])))
out.buf = nil
if err != nil {
Exitf("UnmapViewOfFile failed: %v", err)
diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go
index 00c29c63e0..5cbb7bbacc 100644
--- a/src/cmd/link/internal/ld/pcln.go
+++ b/src/cmd/link/internal/ld/pcln.go
@@ -161,7 +161,7 @@ func (state *pclnState) computeDeferReturn(target *Target, s loader.Sym) uint32
// set the resumption point to PC_B.
lastWasmAddr = uint32(r.Add())
}
- if r.Type().IsDirectCall() && r.Sym() == state.deferReturnSym {
+ if r.Type().IsDirectCall() && (r.Sym() == state.deferReturnSym || state.ldr.IsDeferReturnTramp(r.Sym())) {
if target.IsWasm() {
deferreturn = lastWasmAddr - 1
} else {
diff --git a/src/cmd/link/internal/ld/pe.go b/src/cmd/link/internal/ld/pe.go
index 362d2fd0a5..c9cb25dbe5 100644
--- a/src/cmd/link/internal/ld/pe.go
+++ b/src/cmd/link/internal/ld/pe.go
@@ -1470,6 +1470,7 @@ func setpersrc(ctxt *Link, sym loader.Sym) {
}
rsrcsym = sym
+ ctxt.loader.SetAttrReachable(rsrcsym, true)
}
func addpersrc(ctxt *Link) {
@@ -1477,18 +1478,18 @@ func addpersrc(ctxt *Link) {
return
}
- data := ctxt.loader.Data(rsrcsym)
+ rsrc := ctxt.loader.Syms[rsrcsym]
+ data := rsrc.P
size := len(data)
h := pefile.addSection(".rsrc", size, size)
h.characteristics = IMAGE_SCN_MEM_READ | IMAGE_SCN_MEM_WRITE | IMAGE_SCN_CNT_INITIALIZED_DATA
h.checkOffset(ctxt.Out.Offset())
// relocation
- relocs := ctxt.loader.Relocs(rsrcsym)
- for i := 0; i < relocs.Count(); i++ {
- r := relocs.At2(i)
- p := data[r.Off():]
- val := uint32(int64(h.virtualAddress) + r.Add())
+ for ri := range rsrc.R {
+ r := &rsrc.R[ri]
+ p := data[r.Off:]
+ val := uint32(int64(h.virtualAddress) + r.Add)
// 32-bit little-endian
p[0] = byte(val)
diff --git a/src/cmd/link/internal/ld/sym.go b/src/cmd/link/internal/ld/sym.go
index 7a6c4e43e9..1b7d9d53ee 100644
--- a/src/cmd/link/internal/ld/sym.go
+++ b/src/cmd/link/internal/ld/sym.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/symtab.go b/src/cmd/link/internal/ld/symtab.go
index f9eb05146f..46aa33bcb1 100644
--- a/src/cmd/link/internal/ld/symtab.go
+++ b/src/cmd/link/internal/ld/symtab.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ld/testdata/issue38192/main.go b/src/cmd/link/internal/ld/testdata/issue38192/main.go
new file mode 100644
index 0000000000..3b7df60f15
--- /dev/null
+++ b/src/cmd/link/internal/ld/testdata/issue38192/main.go
@@ -0,0 +1,11 @@
+// Copyright 2020 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 singleInstruction()
+
+func main() {
+ singleInstruction()
+}
diff --git a/src/cmd/link/internal/ld/testdata/issue38192/oneline.s b/src/cmd/link/internal/ld/testdata/issue38192/oneline.s
new file mode 100644
index 0000000000..f5290d7f2e
--- /dev/null
+++ b/src/cmd/link/internal/ld/testdata/issue38192/oneline.s
@@ -0,0 +1,8 @@
+// Copyright 2020 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 "textflag.h"
+
+TEXT ·singleInstruction(SB),NOSPLIT,$0
+ RET
diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go
index 2627218ced..32c342e545 100644
--- a/src/cmd/link/internal/loader/loader.go
+++ b/src/cmd/link/internal/loader/loader.go
@@ -236,7 +236,8 @@ type Loader struct {
outdata [][]byte // symbol's data in the output buffer
extRelocs [][]ExtReloc // symbol's external relocations
- itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
+ itablink map[Sym]struct{} // itablink[j] defined if j is go.itablink.*
+ deferReturnTramp map[Sym]bool // whether the symbol is a trampoline of a deferreturn call
objByPkg map[string]*oReader // map package path to its Go object reader
@@ -362,6 +363,7 @@ func NewLoader(flags uint32, elfsetstring elfsetstringFunc, reporter *ErrorRepor
attrCgoExportDynamic: make(map[Sym]struct{}),
attrCgoExportStatic: make(map[Sym]struct{}),
itablink: make(map[Sym]struct{}),
+ deferReturnTramp: make(map[Sym]bool),
extStaticSyms: make(map[nameVer]Sym),
builtinSyms: make([]Sym, nbuiltin),
flags: flags,
@@ -632,15 +634,15 @@ func (l *Loader) checkdup(name string, r *oReader, li int, dup Sym) {
}
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.unit.Lib, name, rdup.unit.Lib, reason)
- // For the moment, whitelist DWARF subprogram DIEs for
+ // For the moment, allow DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
- whitelist := strings.HasPrefix(name, "go.info.go.interface") ||
+ allowed := strings.HasPrefix(name, "go.info.go.interface") ||
strings.HasPrefix(name, "go.info.go.builtin") ||
strings.HasPrefix(name, "go.debuglines")
- if !whitelist {
+ if !allowed {
l.strictDupMsgs++
}
}
@@ -1062,6 +1064,16 @@ func (l *Loader) IsItabLink(i Sym) bool {
return false
}
+// Return whether this is a trampoline of a deferreturn call.
+func (l *Loader) IsDeferReturnTramp(i Sym) bool {
+ return l.deferReturnTramp[i]
+}
+
+// Set that i is a trampoline of a deferreturn call.
+func (l *Loader) SetIsDeferReturnTramp(i Sym, v bool) {
+ l.deferReturnTramp[i] = v
+}
+
// growValues grows the slice used to store symbol values.
func (l *Loader) growValues(reqLen int) {
curLen := len(l.values)
@@ -1902,7 +1914,7 @@ func (l *Loader) FuncInfo(i Sym) FuncInfo {
// Does not read symbol data.
// Returns the fingerprint of the object.
func (l *Loader) Preload(syms *sym.Symbols, f *bio.Reader, lib *sym.Library, unit *sym.CompilationUnit, length int64) goobj2.FingerprintType {
- roObject, readonly, err := f.Slice(uint64(length))
+ roObject, readonly, err := f.Slice(uint64(length)) // TODO: no need to map blocks that are for tools only (e.g. RefName)
if err != nil {
log.Fatal("cannot read object file:", err)
}
diff --git a/src/cmd/link/internal/mips/asm.go b/src/cmd/link/internal/mips/asm.go
index a366e80ea3..9710b9cffa 100644
--- a/src/cmd/link/internal/mips/asm.go
+++ b/src/cmd/link/internal/mips/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/mips/l.go b/src/cmd/link/internal/mips/l.go
index adbde40f7c..affc48cc06 100644
--- a/src/cmd/link/internal/mips/l.go
+++ b/src/cmd/link/internal/mips/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/mips/obj.go b/src/cmd/link/internal/mips/obj.go
index b646adaf40..f95c776190 100644
--- a/src/cmd/link/internal/mips/obj.go
+++ b/src/cmd/link/internal/mips/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/mips64/asm.go b/src/cmd/link/internal/mips64/asm.go
index e69db29809..b48241b5ae 100644
--- a/src/cmd/link/internal/mips64/asm.go
+++ b/src/cmd/link/internal/mips64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/mips64/l.go b/src/cmd/link/internal/mips64/l.go
index d794122f0b..837af0eb05 100644
--- a/src/cmd/link/internal/mips64/l.go
+++ b/src/cmd/link/internal/mips64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/mips64/obj.go b/src/cmd/link/internal/mips64/obj.go
index b5f7ae1405..5efa356412 100644
--- a/src/cmd/link/internal/mips64/obj.go
+++ b/src/cmd/link/internal/mips64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ppc64/asm.go b/src/cmd/link/internal/ppc64/asm.go
index 4dc50eab79..b1c0873d7a 100644
--- a/src/cmd/link/internal/ppc64/asm.go
+++ b/src/cmd/link/internal/ppc64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -686,16 +686,20 @@ func trampoline(ctxt *ld.Link, ldr *loader.Loader, ri int, rs, s loader.Sym) {
// target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
// distinct trampolines.
- name := ldr.SymName(rs)
+ oName := ldr.SymName(rs)
+ name := oName
if r.Add() == 0 {
- name = name + fmt.Sprintf("-tramp%d", i)
+ name += fmt.Sprintf("-tramp%d", i)
} else {
- name = name + fmt.Sprintf("%+x-tramp%d", r.Add(), i)
+ name += fmt.Sprintf("%+x-tramp%d", r.Add(), i)
}
// Look up the trampoline in case it already exists
tramp = ldr.LookupOrCreateSym(name, int(ldr.SymVersion(rs)))
+ if oName == "runtime.deferreturn" {
+ ldr.SetIsDeferReturnTramp(tramp, true)
+ }
if ldr.SymValue(tramp) == 0 {
break
}
@@ -1098,11 +1102,6 @@ func asmb(ctxt *ld.Link, _ *loader.Loader) {
}
}
- for _, sect := range ld.Segtext.Sections[1:] {
- offset := sect.Vaddr - ld.Segtext.Vaddr + ld.Segtext.Fileoff
- ld.WriteParallel(&wg, ld.Datblk, ctxt, offset, sect.Vaddr, sect.Length)
- }
-
if ld.Segrodata.Filelen > 0 {
ld.WriteParallel(&wg, ld.Datblk, ctxt, ld.Segrodata.Fileoff, ld.Segrodata.Vaddr, ld.Segrodata.Filelen)
}
diff --git a/src/cmd/link/internal/ppc64/l.go b/src/cmd/link/internal/ppc64/l.go
index c78535be58..e8d3b686a4 100644
--- a/src/cmd/link/internal/ppc64/l.go
+++ b/src/cmd/link/internal/ppc64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/ppc64/obj.go b/src/cmd/link/internal/ppc64/obj.go
index 67002bc719..3e1d0a136d 100644
--- a/src/cmd/link/internal/ppc64/obj.go
+++ b/src/cmd/link/internal/ppc64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/s390x/asm.go b/src/cmd/link/internal/s390x/asm.go
index bec7705be5..2115b5fc65 100644
--- a/src/cmd/link/internal/s390x/asm.go
+++ b/src/cmd/link/internal/s390x/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/s390x/l.go b/src/cmd/link/internal/s390x/l.go
index 87d10ee782..f040587547 100644
--- a/src/cmd/link/internal/s390x/l.go
+++ b/src/cmd/link/internal/s390x/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/s390x/obj.go b/src/cmd/link/internal/s390x/obj.go
index 129c6a7ee4..d4ac5afe88 100644
--- a/src/cmd/link/internal/s390x/obj.go
+++ b/src/cmd/link/internal/s390x/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/sym/segment.go b/src/cmd/link/internal/sym/segment.go
index 662e8e0c8f..5aa0bc5e53 100644
--- a/src/cmd/link/internal/sym/segment.go
+++ b/src/cmd/link/internal/sym/segment.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/sym/symbols.go b/src/cmd/link/internal/sym/symbols.go
index ff139fedff..721828d87a 100644
--- a/src/cmd/link/internal/sym/symbols.go
+++ b/src/cmd/link/internal/sym/symbols.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/sym/symkind.go b/src/cmd/link/internal/sym/symkind.go
index 1933dd7b21..3a1cad9b93 100644
--- a/src/cmd/link/internal/sym/symkind.go
+++ b/src/cmd/link/internal/sym/symkind.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/x86/asm.go b/src/cmd/link/internal/x86/asm.go
index 21ea5780cb..b218ffae83 100644
--- a/src/cmd/link/internal/x86/asm.go
+++ b/src/cmd/link/internal/x86/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/x86/l.go b/src/cmd/link/internal/x86/l.go
index 0f104eab57..5875d45f8d 100644
--- a/src/cmd/link/internal/x86/l.go
+++ b/src/cmd/link/internal/x86/l.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/internal/x86/obj.go b/src/cmd/link/internal/x86/obj.go
index 06a1a6a96d..cd33f441e1 100644
--- a/src/cmd/link/internal/x86/obj.go
+++ b/src/cmd/link/internal/x86/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go
index 1c9e177911..dc7adcb5fb 100644
--- a/src/cmd/link/link_test.go
+++ b/src/cmd/link/link_test.go
@@ -629,10 +629,23 @@ func TestFuncAlign(t *testing.T) {
}
}
-const helloSrc = `
+const testTrampSrc = `
package main
import "fmt"
-func main() { fmt.Println("hello") }
+func main() {
+ fmt.Println("hello")
+
+ defer func(){
+ if e := recover(); e == nil {
+ panic("did not panic")
+ }
+ }()
+ f1()
+}
+
+// Test deferreturn trampolines. See issue #39049.
+func f1() { defer f2() }
+func f2() { panic("XXX") }
`
func TestTrampoline(t *testing.T) {
@@ -655,7 +668,7 @@ func TestTrampoline(t *testing.T) {
defer os.RemoveAll(tmpdir)
src := filepath.Join(tmpdir, "hello.go")
- err = ioutil.WriteFile(src, []byte(helloSrc), 0666)
+ err = ioutil.WriteFile(src, []byte(testTrampSrc), 0666)
if err != nil {
t.Fatal(err)
}
@@ -733,3 +746,37 @@ func TestIndexMismatch(t *testing.T) {
t.Errorf("did not see expected error message. out:\n%s", out)
}
}
+
+func TestPErsrc(t *testing.T) {
+ // Test that PE rsrc section is handled correctly (issue 39658).
+ testenv.MustHaveGoBuild(t)
+
+ if runtime.GOARCH != "amd64" || runtime.GOOS != "windows" {
+ t.Skipf("this is a windows/amd64-only test")
+ }
+
+ tmpdir, err := ioutil.TempDir("", "TestPErsrc")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(tmpdir)
+
+ pkgdir := filepath.Join("testdata", "testPErsrc")
+ exe := filepath.Join(tmpdir, "a.exe")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", exe)
+ cmd.Dir = pkgdir
+ // cmd.Env = append(os.Environ(), "GOOS=windows", "GOARCH=amd64") // uncomment if debugging in a cross-compiling environment
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("building failed: %v, output:\n%s", err, out)
+ }
+
+ // Check that the binary contains the rsrc data
+ b, err := ioutil.ReadFile(exe)
+ if err != nil {
+ t.Fatalf("reading output failed: %v", err)
+ }
+ if !bytes.Contains(b, []byte("Hello Gophers!")) {
+ t.Fatalf("binary does not contain expected content")
+ }
+}
diff --git a/src/cmd/link/testdata/testPErsrc/main.go b/src/cmd/link/testdata/testPErsrc/main.go
new file mode 100644
index 0000000000..5eb66fb9cc
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc/main.go
@@ -0,0 +1,19 @@
+// Copyright 2020 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 a PE rsrc section is handled correctly (issue 39658).
+//
+// rsrc.syso is created with:
+// windres -i a.rc -o rsrc.syso -O coff
+// on windows-amd64-2016 builder, where a.rc is a text file with
+// the following content:
+//
+// resname RCDATA {
+// "Hello Gophers!\0",
+// "This is a test.\0",
+// }
+
+package main
+
+func main() {}
diff --git a/src/cmd/link/testdata/testPErsrc/rsrc.syso b/src/cmd/link/testdata/testPErsrc/rsrc.syso
new file mode 100644
index 0000000000..0d9699da04
--- /dev/null
+++ b/src/cmd/link/testdata/testPErsrc/rsrc.syso
Binary files differ
diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go
index a49423b212..5d7fff0f99 100644
--- a/src/cmd/nm/nm_test.go
+++ b/src/cmd/nm/nm_test.go
@@ -315,7 +315,7 @@ func testGoLib(t *testing.T, iscgo bool) {
}
for i := range syms {
sym := &syms[i]
- if sym.Type == typ && matchSymName(name, sym.Name) && sym.CSym == csym {
+ if sym.Type == typ && sym.Name == name && sym.CSym == csym {
if sym.Found {
t.Fatalf("duplicate symbol %s %s", sym.Type, sym.Name)
}
@@ -334,14 +334,6 @@ func TestGoLib(t *testing.T) {
testGoLib(t, false)
}
-// Check that a symbol has a given name, accepting both
-// new and old objects.
-// TODO(go115newobj): remove.
-func matchSymName(symname, want string) bool {
- return symname == want ||
- strings.HasPrefix(symname, want+"#") // new style, with index
-}
-
const testexec = `
package main
diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go
index 814cbf4564..a9dc7d1a5e 100644
--- a/src/cmd/objdump/objdump_test.go
+++ b/src/cmd/objdump/objdump_test.go
@@ -14,7 +14,6 @@ import (
"os"
"os/exec"
"path/filepath"
- "regexp"
"runtime"
"strings"
"testing"
@@ -139,7 +138,11 @@ func testDisasm(t *testing.T, printCode bool, printGnuAsm bool, flags ...string)
args = append(args, flags...)
args = append(args, "fmthello.go")
cmd := exec.Command(testenv.GoToolPath(t), args...)
- cmd.Dir = "testdata" // "Bad line" bug #36683 is sensitive to being run in the source directory
+ // "Bad line" bug #36683 is sensitive to being run in the source directory.
+ cmd.Dir = "testdata"
+ // Ensure that the source file location embedded in the binary matches our
+ // actual current GOROOT, instead of GOROOT_FINAL if set.
+ cmd.Env = append(os.Environ(), "GOROOT_FINAL=")
t.Logf("Running %v", cmd.Args)
out, err := cmd.CombinedOutput()
if err != nil {
@@ -285,11 +288,9 @@ func TestDisasmGoobj(t *testing.T) {
if err != nil {
t.Fatalf("go tool compile fmthello.go: %v\n%s", err, out)
}
-
- // TODO(go115newobj): drop old object file support.
need := []string{
- `main(#\d+)?\(SB\)`, // either new or old object file
- `fmthello\.go:6`,
+ "main(SB)",
+ "fmthello.go:6",
}
args = []string{
@@ -305,9 +306,8 @@ func TestDisasmGoobj(t *testing.T) {
text := string(out)
ok := true
for _, s := range need {
- re := regexp.MustCompile(s)
- if !re.MatchString(text) {
- t.Errorf("disassembly missing %q", s)
+ if !strings.Contains(text, s) {
+ t.Errorf("disassembly missing '%s'", s)
ok = false
}
}
diff --git a/src/cmd/oldlink/internal/amd64/asm.go b/src/cmd/oldlink/internal/amd64/asm.go
index c120e4ea81..13baf3ea7b 100644
--- a/src/cmd/oldlink/internal/amd64/asm.go
+++ b/src/cmd/oldlink/internal/amd64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/amd64/l.go b/src/cmd/oldlink/internal/amd64/l.go
index 393da6bf28..a9afb3a39f 100644
--- a/src/cmd/oldlink/internal/amd64/l.go
+++ b/src/cmd/oldlink/internal/amd64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/amd64/obj.go b/src/cmd/oldlink/internal/amd64/obj.go
index 655d9f1e03..ab85ab22b6 100644
--- a/src/cmd/oldlink/internal/amd64/obj.go
+++ b/src/cmd/oldlink/internal/amd64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/arm/asm.go b/src/cmd/oldlink/internal/arm/asm.go
index de6173569a..77338e4672 100644
--- a/src/cmd/oldlink/internal/arm/asm.go
+++ b/src/cmd/oldlink/internal/arm/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -390,8 +390,12 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
offset := (signext24(r.Add&0xffffff) + 2) * 4
var tramp *sym.Symbol
for i := 0; ; i++ {
- name := r.Sym.Name + fmt.Sprintf("%+d-tramp%d", offset, i)
+ oName := r.Sym.Name
+ name := oName + fmt.Sprintf("%+d-tramp%d", offset, i)
tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
+ if oName == "runtime.deferreturn" {
+ tramp.Attr.Set(sym.AttrDeferReturnTramp, true)
+ }
if tramp.Type == sym.SDYNIMPORT {
// don't reuse trampoline defined in other module
continue
diff --git a/src/cmd/oldlink/internal/arm/l.go b/src/cmd/oldlink/internal/arm/l.go
index a83d26bf06..d16dc2726e 100644
--- a/src/cmd/oldlink/internal/arm/l.go
+++ b/src/cmd/oldlink/internal/arm/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -33,7 +33,7 @@ package arm
// Writing object files.
// Inferno utils/5l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/arm/obj.go b/src/cmd/oldlink/internal/arm/obj.go
index c423937355..397990fd7f 100644
--- a/src/cmd/oldlink/internal/arm/obj.go
+++ b/src/cmd/oldlink/internal/arm/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/arm64/asm.go b/src/cmd/oldlink/internal/arm64/asm.go
index a97671222d..4f29fbed1a 100644
--- a/src/cmd/oldlink/internal/arm64/asm.go
+++ b/src/cmd/oldlink/internal/arm64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/arm64/l.go b/src/cmd/oldlink/internal/arm64/l.go
index 5f3530335e..4aa2708df6 100644
--- a/src/cmd/oldlink/internal/arm64/l.go
+++ b/src/cmd/oldlink/internal/arm64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/arm64/obj.go b/src/cmd/oldlink/internal/arm64/obj.go
index 2dcc999dd1..b5be5ec8fe 100644
--- a/src/cmd/oldlink/internal/arm64/obj.go
+++ b/src/cmd/oldlink/internal/arm64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/ar.go b/src/cmd/oldlink/internal/ld/ar.go
index 8df859f11c..453e12ba98 100644
--- a/src/cmd/oldlink/internal/ld/ar.go
+++ b/src/cmd/oldlink/internal/ld/ar.go
@@ -1,5 +1,5 @@
// Inferno utils/include/ar.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/include/ar.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/include/ar.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/data.go b/src/cmd/oldlink/internal/ld/data.go
index ba4a74156b..02230cbbe1 100644
--- a/src/cmd/oldlink/internal/ld/data.go
+++ b/src/cmd/oldlink/internal/ld/data.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/decodesym.go b/src/cmd/oldlink/internal/ld/decodesym.go
index 0676e94e2c..6c596ec78e 100644
--- a/src/cmd/oldlink/internal/ld/decodesym.go
+++ b/src/cmd/oldlink/internal/ld/decodesym.go
@@ -11,6 +11,7 @@ import (
"cmd/oldlink/internal/sym"
"debug/elf"
"fmt"
+ "log"
)
// Decoding the type.* symbols. This has to be in sync with
@@ -93,7 +94,7 @@ func decodetypeHasUncommon(arch *sys.Arch, p []byte) bool {
func findShlibSection(ctxt *Link, path string, addr uint64) *elf.Section {
for _, shlib := range ctxt.Shlibs {
if shlib.Path == path {
- for _, sect := range shlib.File.Sections {
+ for _, sect := range shlib.File.Sections[1:] { // skip the NULL section
if sect.Addr <= addr && addr <= sect.Addr+sect.Size {
return sect
}
@@ -112,9 +113,15 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
// A gcprog is a 4-byte uint32 indicating length, followed by
// the actual program.
progsize := make([]byte, 4)
- sect.ReadAt(progsize, int64(addr-sect.Addr))
+ _, err := sect.ReadAt(progsize, int64(addr-sect.Addr))
+ if err != nil {
+ log.Fatal(err)
+ }
progbytes := make([]byte, ctxt.Arch.ByteOrder.Uint32(progsize))
- sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+ _, err = sect.ReadAt(progbytes, int64(addr-sect.Addr+4))
+ if err != nil {
+ log.Fatal(err)
+ }
return append(progsize, progbytes...)
}
Exitf("cannot find gcprog for %s", s.Name)
@@ -124,14 +131,6 @@ func decodetypeGcprog(ctxt *Link, s *sym.Symbol) []byte {
}
func decodetypeGcprogShlib(ctxt *Link, s *sym.Symbol) uint64 {
- if ctxt.Arch.Family == sys.ARM64 {
- for _, shlib := range ctxt.Shlibs {
- if shlib.Path == s.File {
- return shlib.gcdataAddresses[s]
- }
- }
- return 0
- }
return decodeInuxi(ctxt.Arch, s.P[2*int32(ctxt.Arch.PtrSize)+8+1*int32(ctxt.Arch.PtrSize):], ctxt.Arch.PtrSize)
}
@@ -141,8 +140,15 @@ func decodetypeGcmask(ctxt *Link, s *sym.Symbol) []byte {
ptrdata := decodetypePtrdata(ctxt.Arch, s.P)
sect := findShlibSection(ctxt, s.File, addr)
if sect != nil {
- r := make([]byte, ptrdata/int64(ctxt.Arch.PtrSize))
- sect.ReadAt(r, int64(addr-sect.Addr))
+ bits := ptrdata / int64(ctxt.Arch.PtrSize)
+ r := make([]byte, (bits+7)/8)
+ // ldshlibsyms avoids closing the ELF file so sect.ReadAt works.
+ // If we remove this read (and the ones in decodetypeGcprog), we
+ // can close the file.
+ _, err := sect.ReadAt(r, int64(addr-sect.Addr))
+ if err != nil {
+ log.Fatal(err)
+ }
return r
}
Exitf("cannot find gcmask for %s", s.Name)
diff --git a/src/cmd/oldlink/internal/ld/ld.go b/src/cmd/oldlink/internal/ld/ld.go
index 7420dce9de..844580b6eb 100644
--- a/src/cmd/oldlink/internal/ld/ld.go
+++ b/src/cmd/oldlink/internal/ld/ld.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/lib.go b/src/cmd/oldlink/internal/ld/lib.go
index 0fc786f1bf..499602f9be 100644
--- a/src/cmd/oldlink/internal/ld/lib.go
+++ b/src/cmd/oldlink/internal/ld/lib.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -66,7 +66,7 @@ import (
// Data layout and relocation.
// Derived from Inferno utils/6l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -2010,7 +2010,9 @@ func ldshlibsyms(ctxt *Link, shlib string) {
Errorf(nil, "cannot open shared library: %s", libpath)
return
}
- defer f.Close()
+ // Keep the file open as decodetypeGcprog needs to read from it.
+ // TODO: fix. Maybe mmap the file.
+ //defer f.Close()
hash, err := readnote(f, ELF_NOTE_GO_NAME, ELF_NOTE_GOABIHASH_TAG)
if err != nil {
diff --git a/src/cmd/oldlink/internal/ld/link.go b/src/cmd/oldlink/internal/ld/link.go
index 15878f3267..514abeec88 100644
--- a/src/cmd/oldlink/internal/ld/link.go
+++ b/src/cmd/oldlink/internal/ld/link.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/main.go b/src/cmd/oldlink/internal/ld/main.go
index f7f3700398..fdbb1de066 100644
--- a/src/cmd/oldlink/internal/ld/main.go
+++ b/src/cmd/oldlink/internal/ld/main.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/pcln.go b/src/cmd/oldlink/internal/ld/pcln.go
index 7d53ab8ad4..ed2e8f9e2b 100644
--- a/src/cmd/oldlink/internal/ld/pcln.go
+++ b/src/cmd/oldlink/internal/ld/pcln.go
@@ -276,7 +276,7 @@ func (ctxt *Link) pclntab() {
// set the resumption point to PC_B.
lastWasmAddr = uint32(r.Add)
}
- if r.Type.IsDirectCall() && r.Sym != nil && r.Sym.Name == "runtime.deferreturn" {
+ if r.Type.IsDirectCall() && r.Sym != nil && (r.Sym.Name == "runtime.deferreturn" || r.Sym.Attr.DeferReturnTramp()) {
if ctxt.Arch.Family == sys.Wasm {
deferreturn = lastWasmAddr - 1
} else {
diff --git a/src/cmd/oldlink/internal/ld/sym.go b/src/cmd/oldlink/internal/ld/sym.go
index 4f697d0627..d5b3a5eabd 100644
--- a/src/cmd/oldlink/internal/ld/sym.go
+++ b/src/cmd/oldlink/internal/ld/sym.go
@@ -1,6 +1,6 @@
// Derived from Inferno utils/6l/obj.c and utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ld/symtab.go b/src/cmd/oldlink/internal/ld/symtab.go
index a324fdf600..86c3c22b9b 100644
--- a/src/cmd/oldlink/internal/ld/symtab.go
+++ b/src/cmd/oldlink/internal/ld/symtab.go
@@ -1,5 +1,5 @@
// Inferno utils/6l/span.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/span.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/span.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips/asm.go b/src/cmd/oldlink/internal/mips/asm.go
index 48a2324151..371c1ea0aa 100644
--- a/src/cmd/oldlink/internal/mips/asm.go
+++ b/src/cmd/oldlink/internal/mips/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips/l.go b/src/cmd/oldlink/internal/mips/l.go
index adbde40f7c..affc48cc06 100644
--- a/src/cmd/oldlink/internal/mips/l.go
+++ b/src/cmd/oldlink/internal/mips/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips/obj.go b/src/cmd/oldlink/internal/mips/obj.go
index c80824ff14..a59bc21a59 100644
--- a/src/cmd/oldlink/internal/mips/obj.go
+++ b/src/cmd/oldlink/internal/mips/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips64/asm.go b/src/cmd/oldlink/internal/mips64/asm.go
index 775b74e1fd..7dcf80527a 100644
--- a/src/cmd/oldlink/internal/mips64/asm.go
+++ b/src/cmd/oldlink/internal/mips64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips64/l.go b/src/cmd/oldlink/internal/mips64/l.go
index d794122f0b..837af0eb05 100644
--- a/src/cmd/oldlink/internal/mips64/l.go
+++ b/src/cmd/oldlink/internal/mips64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/mips64/obj.go b/src/cmd/oldlink/internal/mips64/obj.go
index 1ddce45c06..25a515303f 100644
--- a/src/cmd/oldlink/internal/mips64/obj.go
+++ b/src/cmd/oldlink/internal/mips64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/objfile/objfile.go b/src/cmd/oldlink/internal/objfile/objfile.go
index 6882b7694b..fbd7eb740b 100644
--- a/src/cmd/oldlink/internal/objfile/objfile.go
+++ b/src/cmd/oldlink/internal/objfile/objfile.go
@@ -411,16 +411,16 @@ overwrite:
}
fmt.Fprintf(os.Stderr, "cmd/link: while reading object for '%v': duplicate symbol '%s', previous def at '%v', with mismatched payload: %s\n", r.lib, dup, dup.Unit.Lib, reason)
- // For the moment, whitelist DWARF subprogram DIEs for
+ // For the moment, allow DWARF subprogram DIEs for
// auto-generated wrapper functions. What seems to happen
// here is that we get different line numbers on formal
// params; I am guessing that the pos is being inherited
// from the spot where the wrapper is needed.
- whitelist := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
+ allowed := (strings.HasPrefix(dup.Name, "go.info.go.interface") ||
strings.HasPrefix(dup.Name, "go.info.go.builtin") ||
strings.HasPrefix(dup.Name, "go.isstmt.go.builtin") ||
strings.HasPrefix(dup.Name, "go.debuglines"))
- if !whitelist {
+ if !allowed {
r.strictDupMsgs++
}
}
diff --git a/src/cmd/oldlink/internal/ppc64/asm.go b/src/cmd/oldlink/internal/ppc64/asm.go
index 608bdecca6..612f9aa8d2 100644
--- a/src/cmd/oldlink/internal/ppc64/asm.go
+++ b/src/cmd/oldlink/internal/ppc64/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
@@ -667,7 +667,8 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
// target is at some offset within the function. Calls to duff+8 and duff+256 must appear as
// distinct trampolines.
- name := r.Sym.Name
+ oName := r.Sym.Name
+ name := oName
if r.Add == 0 {
name = name + fmt.Sprintf("-tramp%d", i)
} else {
@@ -677,6 +678,9 @@ func trampoline(ctxt *ld.Link, r *sym.Reloc, s *sym.Symbol) {
// Look up the trampoline in case it already exists
tramp = ctxt.Syms.Lookup(name, int(r.Sym.Version))
+ if oName == "runtime.deferreturn" {
+ tramp.Attr.Set(sym.AttrDeferReturnTramp, true)
+ }
if tramp.Value == 0 {
break
}
diff --git a/src/cmd/oldlink/internal/ppc64/l.go b/src/cmd/oldlink/internal/ppc64/l.go
index c78535be58..e8d3b686a4 100644
--- a/src/cmd/oldlink/internal/ppc64/l.go
+++ b/src/cmd/oldlink/internal/ppc64/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/ppc64/obj.go b/src/cmd/oldlink/internal/ppc64/obj.go
index e9da5a36d5..f508fbd43d 100644
--- a/src/cmd/oldlink/internal/ppc64/obj.go
+++ b/src/cmd/oldlink/internal/ppc64/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/s390x/asm.go b/src/cmd/oldlink/internal/s390x/asm.go
index 6c5744dc95..23cda2a0f6 100644
--- a/src/cmd/oldlink/internal/s390x/asm.go
+++ b/src/cmd/oldlink/internal/s390x/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/s390x/l.go b/src/cmd/oldlink/internal/s390x/l.go
index 87d10ee782..f040587547 100644
--- a/src/cmd/oldlink/internal/s390x/l.go
+++ b/src/cmd/oldlink/internal/s390x/l.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/s390x/obj.go b/src/cmd/oldlink/internal/s390x/obj.go
index b4af86bd75..7317cdc8fc 100644
--- a/src/cmd/oldlink/internal/s390x/obj.go
+++ b/src/cmd/oldlink/internal/s390x/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/5l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/5l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/5l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/sym/attribute.go b/src/cmd/oldlink/internal/sym/attribute.go
index 4b69bf32d0..773b6a4ee7 100644
--- a/src/cmd/oldlink/internal/sym/attribute.go
+++ b/src/cmd/oldlink/internal/sym/attribute.go
@@ -81,7 +81,10 @@ const (
// AttrReadOnly indicates whether the symbol's content (Symbol.P) is backed by
// read-only memory.
AttrReadOnly
- // 19 attributes defined so far.
+ // AttrDeferReturnTramp indicates the symbol is a trampoline of a deferreturn
+ // call.
+ AttrDeferReturnTramp
+ // 20 attributes defined so far.
)
func (a Attribute) DuplicateOK() bool { return a&AttrDuplicateOK != 0 }
@@ -103,6 +106,7 @@ func (a Attribute) SubSymbol() bool { return a&AttrSubSymbol != 0 }
func (a Attribute) Container() bool { return a&AttrContainer != 0 }
func (a Attribute) TopFrame() bool { return a&AttrTopFrame != 0 }
func (a Attribute) ReadOnly() bool { return a&AttrReadOnly != 0 }
+func (a Attribute) DeferReturnTramp() bool { return a&AttrDeferReturnTramp != 0 }
func (a Attribute) CgoExport() bool {
return a.CgoExportDynamic() || a.CgoExportStatic()
diff --git a/src/cmd/oldlink/internal/sym/segment.go b/src/cmd/oldlink/internal/sym/segment.go
index d5255bf142..395679ab66 100644
--- a/src/cmd/oldlink/internal/sym/segment.go
+++ b/src/cmd/oldlink/internal/sym/segment.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/sym/symbols.go b/src/cmd/oldlink/internal/sym/symbols.go
index e772496534..9dd0620c5a 100644
--- a/src/cmd/oldlink/internal/sym/symbols.go
+++ b/src/cmd/oldlink/internal/sym/symbols.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/sym/symkind.go b/src/cmd/oldlink/internal/sym/symkind.go
index 1933dd7b21..3a1cad9b93 100644
--- a/src/cmd/oldlink/internal/sym/symkind.go
+++ b/src/cmd/oldlink/internal/sym/symkind.go
@@ -1,5 +1,5 @@
// Derived from Inferno utils/6l/l.h and related files.
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/6l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/6l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/x86/asm.go b/src/cmd/oldlink/internal/x86/asm.go
index e8e52f671f..df8a23639d 100644
--- a/src/cmd/oldlink/internal/x86/asm.go
+++ b/src/cmd/oldlink/internal/x86/asm.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/asm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/asm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/asm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/x86/l.go b/src/cmd/oldlink/internal/x86/l.go
index 0f104eab57..5875d45f8d 100644
--- a/src/cmd/oldlink/internal/x86/l.go
+++ b/src/cmd/oldlink/internal/x86/l.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/l.h
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/l.h
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/l.h
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/oldlink/internal/x86/obj.go b/src/cmd/oldlink/internal/x86/obj.go
index b78ccbaf99..c9ec0bfdb2 100644
--- a/src/cmd/oldlink/internal/x86/obj.go
+++ b/src/cmd/oldlink/internal/x86/obj.go
@@ -1,5 +1,5 @@
// Inferno utils/8l/obj.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/utils/8l/obj.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/utils/8l/obj.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
index fc2916408c..1849a297d8 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/gnu.go
@@ -134,6 +134,19 @@ func GNUSyntax(inst Inst, pc uint64) string {
buf.WriteString("spr")
}
+ case "sync":
+ switch arg := inst.Args[0].(type) {
+ case Imm:
+ switch arg {
+ case 0:
+ buf.WriteString("hwsync")
+ case 1:
+ buf.WriteString("lwsync")
+ case 2:
+ buf.WriteString("ptesync")
+ }
+ }
+ startArg = 2
default:
buf.WriteString(inst.Op.String())
}
@@ -262,6 +275,8 @@ func isLoadStoreOp(op Op) bool {
return true
case LHBRX, LWBRX, STHBRX, STWBRX:
return true
+ case LBARX, LWARX, LHARX, LDARX:
+ return true
}
return false
}
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
index d039d9d500..858f9acbb8 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/plan9.go
@@ -55,10 +55,24 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
// laid out the instruction
switch inst.Op {
default: // dst, sA, sB, ...
- if len(args) == 0 {
+ switch len(args) {
+ case 0:
return op
- } else if len(args) == 1 {
+ case 1:
return fmt.Sprintf("%s %s", op, args[0])
+ case 2:
+ if inst.Op == COPY || inst.Op == PASTECC || inst.Op == FCMPO || inst.Op == FCMPU {
+ return op + " " + args[0] + "," + args[1]
+ }
+ return op + " " + args[1] + "," + args[0]
+ case 3:
+ if reverseOperandOrder(inst.Op) {
+ return op + " " + args[2] + "," + args[1] + "," + args[0]
+ }
+ case 4:
+ if reverseMiddleOps(inst.Op) {
+ return op + " " + args[1] + "," + args[3] + "," + args[2] + "," + args[0]
+ }
}
args = append(args, args[0])
return op + " " + strings.Join(args[1:], ",")
@@ -77,7 +91,7 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
STH, STHU,
STW, STWU,
STD, STDU,
- STQ:
+ STQ, STFD, STFDU, STFS, STFSU:
return op + " " + strings.Join(args, ",")
case CMPD, CMPDI, CMPLD, CMPLDI, CMPW, CMPWI, CMPLW, CMPLWI:
@@ -92,28 +106,41 @@ func GoSyntax(inst Inst, pc uint64, symname func(uint64) (string, uint64)) strin
return "ADDIS $0," + args[1] + "," + args[0]
// store instructions with index registers
case STBX, STBUX, STHX, STHUX, STWX, STWUX, STDX, STDUX,
- STHBRX, STWBRX, STDBRX, STSWX, STFSX, STFSUX, STFDX, STFDUX, STFIWX, STFDPX:
+ STHBRX, STWBRX, STDBRX, STSWX, STFIWX:
return "MOV" + op[2:len(op)-1] + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
case STDCXCC, STWCXCC, STHCXCC, STBCXCC:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
- case STXVD2X, STXVW4X:
+ case STXVD2X, STXVW4X, STXSDX, STVX, STVXL, STVEBX, STVEHX, STVEWX, STXSIWX, STFDX, STFDUX, STFDPX, STFSX, STFSUX:
return op + " " + args[0] + ",(" + args[2] + ")(" + args[1] + ")"
- // load instructions with index registers
- case LBZX, LBZUX, LHZX, LHZUX, LWZX, LWZUX, LDX, LDUX,
- LHBRX, LWBRX, LDBRX, LSWX, LFSX, LFSUX, LFDX, LFDUX, LFIWAX, LFIWZX:
- return "MOV" + op[1:len(op)-1] + " (" + args[2] + ")(" + args[1] + ")," + args[0]
+ case STXV:
+ return op + " " + args[0] + "," + args[1]
+
+ case STXVL, STXVLL:
+ return op + " " + args[0] + "," + args[1] + "," + args[2]
- case LDARX, LWARX, LHARX, LBARX:
+ case LWAX, LWAUX, LWZX, LHZX, LBZX, LDX, LHAX, LHAUX, LDARX, LWARX, LHARX, LBARX, LFDX, LFDUX, LFSX, LFSUX, LDBRX, LWBRX, LHBRX, LDUX, LWZUX, LHZUX, LBZUX:
+ if args[1] == "0" {
+ return op + " (" + args[2] + ")," + args[0]
+ }
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
- case LXVD2X, LXVW4X:
+ case LXVD2X, LXVW4X, LVX, LVXL, LVSR, LVSL, LVEBX, LVEHX, LVEWX, LXSDX, LXSIWAX:
return op + " (" + args[2] + ")(" + args[1] + ")," + args[0]
- case DCBT, DCBTST, DCBZ, DCBST:
- return op + " (" + args[1] + ")"
+ case LXV:
+ return op + " " + args[1] + "," + args[0]
+
+ case LXVL, LXVLL:
+ return op + " " + args[1] + "," + args[2] + "," + args[0]
+
+ case DCBT, DCBTST, DCBZ, DCBST, DCBI, ICBI:
+ if args[0] == "0" || args[0] == "R0" {
+ return op + " (" + args[1] + ")"
+ }
+ return op + " (" + args[1] + ")(" + args[0] + ")"
// branch instructions needs additional handling
case BCLR:
@@ -173,12 +200,15 @@ func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64)
if inst.Op == ISEL {
return fmt.Sprintf("$%d", (arg - Cond0LT))
}
- if arg == CR0 && strings.HasPrefix(inst.Op.String(), "cmp") {
+ if arg == CR0 && (strings.HasPrefix(inst.Op.String(), "cmp") || strings.HasPrefix(inst.Op.String(), "fcmp")) {
return "" // don't show cr0 for cmp instructions
} else if arg >= CR0 {
return fmt.Sprintf("CR%d", int(arg-CR0))
}
bit := [4]string{"LT", "GT", "EQ", "SO"}[(arg-Cond0LT)%4]
+ if strings.HasPrefix(inst.Op.String(), "cr") {
+ return fmt.Sprintf("CR%d%s", int(arg-Cond0LT)/4, bit)
+ }
if arg <= Cond0SO {
return bit
}
@@ -212,6 +242,37 @@ func plan9Arg(inst *Inst, argIndex int, pc uint64, arg Arg, symname func(uint64)
return fmt.Sprintf("???(%v)", arg)
}
+func reverseMiddleOps(op Op) bool {
+ switch op {
+ case FMADD, FMADDCC, FMADDS, FMADDSCC, FMSUB, FMSUBCC, FMSUBS, FMSUBSCC, FNMADD, FNMADDCC, FNMADDS, FNMADDSCC, FNMSUB, FNMSUBCC, FNMSUBS, FNMSUBSCC, FSEL, FSELCC:
+ return true
+ }
+ return false
+}
+
+func reverseOperandOrder(op Op) bool {
+ switch op {
+ // Special case for SUBF, SUBFC: not reversed
+ case ADD, ADDC, ADDE, ADDCC, ADDCCC:
+ return true
+ case MULLW, MULLWCC, MULHW, MULHWCC, MULLD, MULLDCC, MULHD, MULHDCC, MULLWO, MULLWOCC, MULHWU, MULHWUCC, MULLDO, MULLDOCC:
+ return true
+ case DIVD, DIVDCC, DIVDU, DIVDUCC, DIVDE, DIVDECC, DIVDEU, DIVDEUCC, DIVDO, DIVDOCC, DIVDUO, DIVDUOCC:
+ return true
+ case MODUD, MODSD, MODUW, MODSW:
+ return true
+ case FADD, FADDS, FSUB, FSUBS, FMUL, FMULS, FDIV, FDIVS, FMADD, FMADDS, FMSUB, FMSUBS, FNMADD, FNMADDS, FNMSUB, FNMSUBS, FMULSCC:
+ return true
+ case FADDCC, FADDSCC, FSUBCC, FMULCC, FDIVCC, FDIVSCC:
+ return true
+ case OR, ORC, AND, ANDC, XOR, NAND, EQV, NOR, ANDCC, ORCC, XORCC, EQVCC, NORCC, NANDCC:
+ return true
+ case SLW, SLWCC, SLD, SLDCC, SRW, SRAW, SRWCC, SRAWCC, SRD, SRDCC, SRAD, SRADCC:
+ return true
+ }
+ return false
+}
+
// revCondMap maps a conditional register bit to its inverse, if possible.
var revCondMap = map[string]string{
"LT": "GE", "GT": "LE", "EQ": "NE",
@@ -219,15 +280,65 @@ var revCondMap = map[string]string{
// plan9OpMap maps an Op to its Plan 9 mnemonics, if different than its GNU mnemonics.
var plan9OpMap = map[Op]string{
- LWARX: "LWAR",
- LDARX: "LDAR",
- LHARX: "LHAR",
- LBARX: "LBAR",
- ADDI: "ADD",
- SRADI: "SRAD",
- SUBF: "SUB",
- LI: "MOVD",
- LBZ: "MOVBZ", STB: "MOVB",
+ LWARX: "LWAR",
+ LDARX: "LDAR",
+ LHARX: "LHAR",
+ LBARX: "LBAR",
+ LWAX: "MOVW",
+ LHAX: "MOVH",
+ LWAUX: "MOVWU",
+ LHAU: "MOVHU",
+ LHAUX: "MOVHU",
+ LDX: "MOVD",
+ LDUX: "MOVDU",
+ LWZX: "MOVWZ",
+ LWZUX: "MOVWZU",
+ LHZX: "MOVHZ",
+ LHZUX: "MOVHZU",
+ LBZX: "MOVBZ",
+ LBZUX: "MOVBZU",
+ LDBRX: "MOVDBR",
+ LWBRX: "MOVWBR",
+ LHBRX: "MOVHBR",
+ MCRF: "MOVFL",
+ XORI: "XOR",
+ ORI: "OR",
+ ANDICC: "ANDCC",
+ ANDC: "ANDN",
+ ADDEO: "ADDEV",
+ ADDEOCC: "ADDEVCC",
+ ADDO: "ADDV",
+ ADDOCC: "ADDVCC",
+ ADDMEO: "ADDMEV",
+ ADDMEOCC: "ADDMEVCC",
+ ADDCO: "ADDCV",
+ ADDCOCC: "ADDCVCC",
+ ADDZEO: "ADDZEV",
+ ADDZEOCC: "ADDZEVCC",
+ SUBFME: "SUBME",
+ SUBFMECC: "SUBMECC",
+ SUBFZE: "SUBZE",
+ SUBFZECC: "SUBZECC",
+ SUBFZEO: "SUBZEV",
+ SUBFZEOCC: "SUBZEVCC",
+ SUBFC: "SUBC",
+ ORC: "ORN",
+ MULLWO: "MULLWV",
+ MULLWOCC: "MULLWVCC",
+ MULLDO: "MULLDV",
+ MULLDOCC: "MULLDVCC",
+ DIVDO: "DIVDV",
+ DIVDOCC: "DIVDVCC",
+ DIVDUO: "DIVDUV",
+ DIVDUOCC: "DIVDUVCC",
+ ADDI: "ADD",
+ SRADI: "SRAD",
+ SUBF: "SUB",
+ STBCXCC: "STBCCC",
+ STWCXCC: "STWCCC",
+ STDCXCC: "STDCCC",
+ LI: "MOVD",
+ LBZ: "MOVBZ", STB: "MOVB",
LBZU: "MOVBZU", STBU: "MOVBU",
LHZ: "MOVHZ", LHA: "MOVH", STH: "MOVH",
LHZU: "MOVHZU", STHU: "MOVHU",
@@ -235,6 +346,14 @@ var plan9OpMap = map[Op]string{
LWZU: "MOVWZU", STWU: "MOVWU",
LD: "MOVD", STD: "MOVD",
LDU: "MOVDU", STDU: "MOVDU",
+ LFD: "FMOVD", STFD: "FMOVD",
+ LFS: "FMOVS", STFS: "FMOVS",
+ LFDX: "FMOVD", STFDX: "FMOVD",
+ LFDU: "FMOVDU", STFDU: "FMOVDU",
+ LFDUX: "FMOVDU", STFDUX: "FMOVDU",
+ LFSX: "FMOVS", STFSX: "FMOVS",
+ LFSU: "FMOVSU", STFSU: "FMOVSU",
+ LFSUX: "FMOVSU", STFSUX: "FMOVSU",
CMPD: "CMP", CMPDI: "CMP",
CMPW: "CMPW", CMPWI: "CMPW",
CMPLD: "CMPU", CMPLDI: "CMPU",
diff --git a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
index f536926dbc..250d3b7193 100644
--- a/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
+++ b/src/cmd/vendor/golang.org/x/arch/ppc64/ppc64asm/tables.go
@@ -186,6 +186,10 @@ const (
DIVDEUCC
DIVDEUO
DIVDEUOCC
+ MODSD
+ MODUD
+ MODSW
+ MODUW
CMPWI
CMPDI
CMPW
@@ -466,6 +470,7 @@ const (
VSPLTISH
VSPLTISW
VPERM
+ VPERMR
VSEL
VSL
VSLDOI
@@ -524,6 +529,7 @@ const (
VMSUMSHS
VMSUMUHM
VMSUMUHS
+ VMSUMUDM
VSUMSWS
VSUM2SWS
VSUM4SBS
@@ -559,6 +565,18 @@ const (
VCMPEQUWCC
VCMPEQUD
VCMPEQUDCC
+ VCMPNEB
+ VCMPNEBCC
+ VCMPNEZB
+ VCMPNEZBCC
+ VCMPNEH
+ VCMPNEHCC
+ VCMPNEZH
+ VCMPNEZHCC
+ VCMPNEW
+ VCMPNEWCC
+ VCMPNEZW
+ VCMPNEZWCC
VCMPGTSB
VCMPGTSBCC
VCMPGTSD
@@ -647,6 +665,7 @@ const (
VPOPCNTH
VPOPCNTW
VBPERMQ
+ VBPERMD
BCDADDCC
BCDSUBCC
MTVSCR
@@ -708,11 +727,17 @@ const (
LXVD2X
LXVDSX
LXVW4X
+ LXV
+ LXVL
+ LXVLL
STXSDX
STXSIWX
STXSSPX
STXVD2X
STXVW4X
+ STXV
+ STXVL
+ STXVLL
XSABSDP
XSADDDP
XSADDSP
@@ -852,6 +877,7 @@ const (
XXMRGHW
XXMRGLW
XXPERMDI
+ XXPERM
XXSEL
XXSLDWI
XXSPLTW
@@ -1528,6 +1554,10 @@ var opstr = [...]string{
DIVDEUCC: "divdeu.",
DIVDEUO: "divdeuo",
DIVDEUOCC: "divdeuo.",
+ MODSD: "modsd",
+ MODUD: "modud",
+ MODSW: "modsw",
+ MODUW: "moduw",
CMPWI: "cmpwi",
CMPDI: "cmpdi",
CMPW: "cmpw",
@@ -1808,6 +1838,7 @@ var opstr = [...]string{
VSPLTISH: "vspltish",
VSPLTISW: "vspltisw",
VPERM: "vperm",
+ VPERMR: "vpermr",
VSEL: "vsel",
VSL: "vsl",
VSLDOI: "vsldoi",
@@ -1866,6 +1897,7 @@ var opstr = [...]string{
VMSUMSHS: "vmsumshs",
VMSUMUHM: "vmsumuhm",
VMSUMUHS: "vmsumuhs",
+ VMSUMUDM: "vmsumudm",
VSUMSWS: "vsumsws",
VSUM2SWS: "vsum2sws",
VSUM4SBS: "vsum4sbs",
@@ -1901,6 +1933,18 @@ var opstr = [...]string{
VCMPEQUWCC: "vcmpequw.",
VCMPEQUD: "vcmpequd",
VCMPEQUDCC: "vcmpequd.",
+ VCMPNEB: "vcmpneb",
+ VCMPNEBCC: "vcmpneb.",
+ VCMPNEZB: "vcmpnezb",
+ VCMPNEZBCC: "vcmpnezb.",
+ VCMPNEH: "vcmpneh",
+ VCMPNEHCC: "vcmpneh.",
+ VCMPNEZH: "vcmpnezh",
+ VCMPNEZHCC: "vcmpnezh.",
+ VCMPNEW: "vcmpnew",
+ VCMPNEWCC: "vcmpnew.",
+ VCMPNEZW: "vcmpnezw",
+ VCMPNEZWCC: "vcmpnezw.",
VCMPGTSB: "vcmpgtsb",
VCMPGTSBCC: "vcmpgtsb.",
VCMPGTSD: "vcmpgtsd",
@@ -1989,6 +2033,7 @@ var opstr = [...]string{
VPOPCNTH: "vpopcnth",
VPOPCNTW: "vpopcntw",
VBPERMQ: "vbpermq",
+ VBPERMD: "vbpermd",
BCDADDCC: "bcdadd.",
BCDSUBCC: "bcdsub.",
MTVSCR: "mtvscr",
@@ -2050,11 +2095,17 @@ var opstr = [...]string{
LXVD2X: "lxvd2x",
LXVDSX: "lxvdsx",
LXVW4X: "lxvw4x",
+ LXV: "lxv",
+ LXVL: "lxvl",
+ LXVLL: "lxvll",
STXSDX: "stxsdx",
STXSIWX: "stxsiwx",
STXSSPX: "stxsspx",
STXVD2X: "stxvd2x",
STXVW4X: "stxvw4x",
+ STXV: "stxv",
+ STXVL: "stxvl",
+ STXVLL: "stxvll",
XSABSDP: "xsabsdp",
XSADDDP: "xsadddp",
XSADDSP: "xsaddsp",
@@ -2194,6 +2245,7 @@ var opstr = [...]string{
XXMRGHW: "xxmrghw",
XXMRGLW: "xxmrglw",
XXPERMDI: "xxpermdi",
+ XXPERM: "xxperm",
XXSEL: "xxsel",
XXSLDWI: "xxsldwi",
XXSPLTW: "xxspltw",
@@ -2745,6 +2797,7 @@ var (
ap_ImmUnsigned_21_22 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{21, 2}}}
ap_ImmUnsigned_11_12 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 2}}}
ap_ImmUnsigned_11_11 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{11, 1}}}
+ ap_VecSReg_28_28_6_10 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{28, 1}, {6, 5}}}
ap_VecSReg_30_30_16_20 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{30, 1}, {16, 5}}}
ap_VecSReg_29_29_11_15 = &argField{Type: TypeVecSReg, Shift: 0, BitFields: BitFields{{29, 1}, {11, 5}}}
ap_ImmUnsigned_22_23 = &argField{Type: TypeImmUnsigned, Shift: 0, BitFields: BitFields{{22, 2}}}
@@ -3125,6 +3178,14 @@ var instFormats = [...]instFormat{
[5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{DIVDEUOCC, 0xfc0007ff, 0x7c000713, 0x0, // Divide Doubleword Extended Unsigned XO-form (divdeuo. RT,RA,RB)
[5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODSD, 0xfc0007fe, 0x7c000612, 0x1, // Modulo Signed Doubleword X-form (modsd RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODUD, 0xfc0007fe, 0x7c000212, 0x1, // Modulo Unsigned Doubleword X-form (modud RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODSW, 0xfc0007fe, 0x7c000616, 0x1, // Modulo Signed Word X-form (modsw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {MODUW, 0xfc0007fe, 0x7c000216, 0x1, // Modulo Unsigned Word X-form (moduw RT,RA,RB)
+ [5]*argField{ap_Reg_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{CMPWI, 0xfc200000, 0x2c000000, 0x400000, // Compare Immediate D-form (cmpwi BF,RA,SI)
[5]*argField{ap_CondRegField_6_8, ap_Reg_11_15, ap_ImmSigned_16_31}},
{CMPDI, 0xfc200000, 0x2c200000, 0x400000, // Compare Immediate D-form (cmpdi BF,RA,SI)
@@ -3685,6 +3746,8 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecReg_6_10, ap_ImmSigned_11_15}},
{VPERM, 0xfc00003f, 0x1000002b, 0x0, // Vector Permute VA-form (vperm VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VPERMR, 0xfc00003f, 0x1000003b, 0x0, // Vector Permute Right-indexed VA-form (vpermr VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSEL, 0xfc00003f, 0x1000002a, 0x0, // Vector Select VA-form (vsel VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSL, 0xfc0007ff, 0x100001c4, 0x0, // Vector Shift Left VX-form (vsl VRT,VRA,VRB)
@@ -3801,6 +3864,8 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VMSUMUHS, 0xfc00003f, 0x10000027, 0x0, // Vector Multiply-Sum Unsigned Halfword Saturate VA-form (vmsumuhs VRT,VRA,VRB,VRC)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
+ {VMSUMUDM, 0xfc00003f, 0x10000023, 0x0, // Vector Multiply-Sum Unsigned Doubleword Modulo VA-form (vmsumudm VRT,VRA,VRB,VRC)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_VecReg_21_25}},
{VSUMSWS, 0xfc0007ff, 0x10000788, 0x0, // Vector Sum across Signed Word Saturate VX-form (vsumsws VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VSUM2SWS, 0xfc0007ff, 0x10000688, 0x0, // Vector Sum across Half Signed Word Saturate VX-form (vsum2sws VRT,VRA,VRB)
@@ -3871,6 +3936,30 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPEQUDCC, 0xfc0007ff, 0x100004c7, 0x0, // Vector Compare Equal To Unsigned Doubleword VX-form (vcmpequd. VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEB, 0xfc0007ff, 0x10000007, 0x0, // Vector Compare Not Equal Byte VX-form (vcmpneb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEBCC, 0xfc0007ff, 0x10000407, 0x0, // Vector Compare Not Equal Byte VX-form (vcmpneb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZB, 0xfc0007ff, 0x10000107, 0x0, // Vector Compare Not Equal or Zero Byte VX-form (vcmpnezb VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZBCC, 0xfc0007ff, 0x10000507, 0x0, // Vector Compare Not Equal or Zero Byte VX-form (vcmpnezb. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEH, 0xfc0007ff, 0x10000047, 0x0, // Vector Compare Not Equal Halfword VX-form (vcmpneh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEHCC, 0xfc0007ff, 0x10000447, 0x0, // Vector Compare Not Equal Halfword VX-form (vcmpneh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZH, 0xfc0007ff, 0x10000147, 0x0, // Vector Compare Not Equal or Zero Halfword VX-form (vcmpnezh VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZHCC, 0xfc0007ff, 0x10000547, 0x0, // Vector Compare Not Equal or Zero Halfword VX-form (vcmpnezh. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEW, 0xfc0007ff, 0x10000087, 0x0, // Vector Compare Not Equal Word VX-form (vcmpnew VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEWCC, 0xfc0007ff, 0x10000487, 0x0, // Vector Compare Not Equal Word VX-form (vcmpnew. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZW, 0xfc0007ff, 0x10000187, 0x0, // Vector Compare Not Equal or Zero Word VX-form (vcmpnezw VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VCMPNEZWCC, 0xfc0007ff, 0x10000587, 0x0, // Vector Compare Not Equal or Zero Word VX-form (vcmpnezw. VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPGTSB, 0xfc0007ff, 0x10000306, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{VCMPGTSBCC, 0xfc0007ff, 0x10000706, 0x0, // Vector Compare Greater Than Signed Byte VC-form (vcmpgtsb. VRT,VRA,VRB)
@@ -4047,6 +4136,8 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecReg_6_10, ap_VecReg_16_20}},
{VBPERMQ, 0xfc0007ff, 0x1000054c, 0x0, // Vector Bit Permute Quadword VX-form (vbpermq VRT,VRA,VRB)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
+ {VBPERMD, 0xfc0007ff, 0x100005cc, 0x0, // Vector Bit Permute Doubleword VX-form (vbpermd VRT,VRA,VRB)
+ [5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20}},
{BCDADDCC, 0xfc0005ff, 0x10000401, 0x0, // Decimal Add Modulo VX-form (bcdadd. VRT,VRA,VRB,PS)
[5]*argField{ap_VecReg_6_10, ap_VecReg_11_15, ap_VecReg_16_20, ap_ImmUnsigned_22_22}},
{BCDSUBCC, 0xfc0005ff, 0x10000441, 0x0, // Decimal Subtract Modulo VX-form (bcdsub. VRT,VRA,VRB,PS)
@@ -4169,6 +4260,12 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{LXVW4X, 0xfc0007fe, 0x7c000618, 0x0, // Load VSX Vector Word*4 Indexed XX1-form (lxvw4x XT,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXV, 0xfc000007, 0xf4000001, 0x0, // Load VSX Vector DQ-form (lxv XT,DQ(RA))
+ [5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
+ {LXVL, 0xfc0007fe, 0x7c00021a, 0x0, // Load VSX Vector with Length X-form (lxvl XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {LXVLL, 0xfc0007fe, 0x7c00025a, 0x0, // Load VSX Vector Left-justified with Length X-form (lxvll XT,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXSDX, 0xfc0007fe, 0x7c000598, 0x0, // Store VSX Scalar Doubleword Indexed XX1-form (stxsdx XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXSIWX, 0xfc0007fe, 0x7c000118, 0x0, // Store VSX Scalar as Integer Word Indexed XX1-form (stxsiwx XS,RA,RB)
@@ -4179,6 +4276,12 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{STXVW4X, 0xfc0007fe, 0x7c000718, 0x0, // Store VSX Vector Word*4 Indexed XX1-form (stxvw4x XS,RA,RB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXV, 0xfc000007, 0xf4000005, 0x0, // Store VSX Vector DQ-form (stxv XS,DQ(RA))
+ [5]*argField{ap_VecSReg_28_28_6_10, ap_Offset_16_27_shift4, ap_Reg_11_15}},
+ {STXVL, 0xfc0007fe, 0x7c00031a, 0x0, // Store VSX Vector with Length X-form (stxvl XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
+ {STXVLL, 0xfc0007fe, 0x7c00035a, 0x0, // Store VSX Vector Left-justified with Length X-form (stxvll XS,RA,RB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_Reg_11_15, ap_Reg_16_20}},
{XSABSDP, 0xfc0007fc, 0xf0000564, 0x1f0000, // VSX Scalar Absolute Value Double-Precision XX2-form (xsabsdp XT,XB)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_30_30_16_20}},
{XSADDDP, 0xfc0007f8, 0xf0000100, 0x0, // VSX Scalar Add Double-Precision XX3-form (xsadddp XT,XA,XB)
@@ -4457,6 +4560,8 @@ var instFormats = [...]instFormat{
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
{XXPERMDI, 0xfc0004f8, 0xf0000050, 0x0, // VSX Permute Doubleword Immediate XX3-form (xxpermdi XT,XA,XB,DM)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_ImmUnsigned_22_23}},
+ {XXPERM, 0xfc0007f8, 0xf00000d0, 0x0, // VSX Permute XX3-form (xxperm XT,XA,XB)
+ [5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20}},
{XXSEL, 0xfc000030, 0xf0000030, 0x0, // VSX Select XX4-form (xxsel XT,XA,XB,XC)
[5]*argField{ap_VecSReg_31_31_6_10, ap_VecSReg_29_29_11_15, ap_VecSReg_30_30_16_20, ap_VecSReg_28_28_21_25}},
{XXSLDWI, 0xfc0004f8, 0xf0000010, 0x0, // VSX Shift Left Double by Word Immediate XX3-form (xxsldwi XT,XA,XB,SHW)
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
index ea56b724e8..fb17a0e415 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/doc.go
@@ -170,6 +170,15 @@ Diagnostic is defined as:
The optional Category field is a short identifier that classifies the
kind of message when an analysis produces several kinds of diagnostic.
+Many analyses want to associate diagnostics with a severity level.
+Because Diagnostic does not have a severity level field, an Analyzer's
+diagnostics effectively all have the same severity level. To separate which
+diagnostics are high severity and which are low severity, expose multiple
+Analyzers instead. Analyzers should also be separated when their
+diagnostics belong in different groups, or could be tagged differently
+before being shown to the end user. Analyzers should document their severity
+level to help downstream tools surface diagnostics properly.
+
Most Analyzers inspect typed Go syntax trees, but a few, such as asmdecl
and buildtag, inspect the raw text of Go source files or even non-Go
files such as assembly. To report a diagnostic against a line of a
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
index 14f3a47610..ddad4c796c 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/printf/printf.go
@@ -805,6 +805,7 @@ var printVerbs = []printVerb{
{'g', sharpNumFlag, argFloat | argComplex},
{'G', sharpNumFlag, argFloat | argComplex},
{'o', sharpNumFlag, argInt | argPointer},
+ {'O', sharpNumFlag, argInt | argPointer},
{'p', "-#", argPointer},
{'q', " -+.0#", argRune | argInt | argString},
{'s', " -+.0", argString},
diff --git a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
index ac2cd84ad3..7a005901e8 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/analysis/passes/stringintconv/string.go
@@ -101,7 +101,7 @@ func run(pass *analysis.Pass) (interface{}, error) {
}
diag := analysis.Diagnostic{
Pos: n.Pos(),
- Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune", source, target),
+ Message: fmt.Sprintf("conversion from %s to %s yields a string of one rune, not a string of digits (did you mean fmt.Sprint(x)?)", source, target),
SuggestedFixes: []analysis.SuggestedFix{
{
Message: "Did you mean to convert a rune to a string?",
diff --git a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
index 882e3b3d8a..cffd7acbee 100644
--- a/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
+++ b/src/cmd/vendor/golang.org/x/tools/go/types/objectpath/objectpath.go
@@ -226,7 +226,8 @@ func For(obj types.Object) (Path, error) {
// the best paths because non-types may
// refer to types, but not the reverse.
empty := make([]byte, 0, 48) // initial space
- for _, name := range scope.Names() {
+ names := scope.Names()
+ for _, name := range names {
o := scope.Lookup(name)
tname, ok := o.(*types.TypeName)
if !ok {
@@ -253,7 +254,7 @@ func For(obj types.Object) (Path, error) {
// Then inspect everything else:
// non-types, and declared methods of defined types.
- for _, name := range scope.Names() {
+ for _, name := range names {
o := scope.Lookup(name)
path := append(empty, name...)
if _, ok := o.(*types.TypeName); !ok {
diff --git a/src/cmd/vendor/modules.txt b/src/cmd/vendor/modules.txt
index 10d7d4b9f1..7ee7478b19 100644
--- a/src/cmd/vendor/modules.txt
+++ b/src/cmd/vendor/modules.txt
@@ -18,18 +18,18 @@ github.com/google/pprof/third_party/svgpan
# github.com/ianlancetaylor/demangle v0.0.0-20200414190113-039b1ae3a340
## explicit
github.com/ianlancetaylor/demangle
-# golang.org/x/arch v0.0.0-20200312215426-ff8b605520f4
+# golang.org/x/arch v0.0.0-20200511175325-f7c78586839d
## explicit
golang.org/x/arch/arm/armasm
golang.org/x/arch/arm64/arm64asm
golang.org/x/arch/ppc64/ppc64asm
golang.org/x/arch/x86/x86asm
-# golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
+# golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
## explicit
golang.org/x/crypto/ed25519
golang.org/x/crypto/ed25519/internal/edwards25519
golang.org/x/crypto/ssh/terminal
-# golang.org/x/mod v0.2.1-0.20200429172858-859b3ef565e2
+# golang.org/x/mod v0.3.0
## explicit
golang.org/x/mod/internal/lazyregexp
golang.org/x/mod/modfile
@@ -45,7 +45,7 @@ golang.org/x/mod/zip
golang.org/x/sys/internal/unsafeheader
golang.org/x/sys/unix
golang.org/x/sys/windows
-# golang.org/x/tools v0.0.0-20200504152539-33427f1b0364
+# golang.org/x/tools v0.0.0-20200616133436-c1934b75d054
## explicit
golang.org/x/tools/go/analysis
golang.org/x/tools/go/analysis/internal/analysisflags
diff --git a/src/container/list/list.go b/src/container/list/list.go
index cc9ff0988c..210424ceed 100644
--- a/src/container/list/list.go
+++ b/src/container/list/list.go
@@ -219,7 +219,7 @@ func (l *List) MoveAfter(e, mark *Element) {
l.move(e, mark)
}
-// PushBackList inserts a copy of an other list at the back of list l.
+// PushBackList inserts a copy of another list at the back of list l.
// The lists l and other may be the same. They must not be nil.
func (l *List) PushBackList(other *List) {
l.lazyInit()
@@ -228,7 +228,7 @@ func (l *List) PushBackList(other *List) {
}
}
-// PushFrontList inserts a copy of an other list at the front of list l.
+// PushFrontList inserts a copy of another list at the front of list l.
// The lists l and other may be the same. They must not be nil.
func (l *List) PushFrontList(other *List) {
l.lazyInit()
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
index bd5168c5fd..f93dc16419 100644
--- a/src/crypto/elliptic/elliptic.go
+++ b/src/crypto/elliptic/elliptic.go
@@ -20,7 +20,10 @@ import (
)
// A Curve represents a short-form Weierstrass curve with a=-3.
-// See https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+//
+// Note that the point at infinity (0, 0) is not considered on the curve, and
+// although it can be returned by Add, Double, ScalarMult, or ScalarBaseMult, it
+// can't be marshaled or unmarshaled, and IsOnCurve will return false for it.
type Curve interface {
// Params returns the parameters for the curve.
Params() *CurveParams
@@ -52,11 +55,8 @@ func (curve *CurveParams) Params() *CurveParams {
return curve
}
-func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
- // y² = x³ - 3x + b
- y2 := new(big.Int).Mul(y, y)
- y2.Mod(y2, curve.P)
-
+// polynomial returns x³ - 3x + b.
+func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
x3 := new(big.Int).Mul(x, x)
x3.Mul(x3, x)
@@ -67,7 +67,15 @@ func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
x3.Add(x3, curve.B)
x3.Mod(x3, curve.P)
- return x3.Cmp(y2) == 0
+ return x3
+}
+
+func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
+ // y² = x³ - 3x + b
+ y2 := new(big.Int).Mul(y, y)
+ y2.Mod(y2, curve.P)
+
+ return curve.polynomial(x).Cmp(y2) == 0
}
// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
@@ -302,7 +310,8 @@ func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err e
return
}
-// Marshal converts a point into the uncompressed form specified in section 4.3.6 of ANSI X9.62.
+// Marshal converts a point on the curve into the uncompressed form specified in
+// section 4.3.6 of ANSI X9.62.
func Marshal(curve Curve, x, y *big.Int) []byte {
byteLen := (curve.Params().BitSize + 7) / 8
@@ -315,16 +324,26 @@ func Marshal(curve Curve, x, y *big.Int) []byte {
return ret
}
+// MarshalCompressed converts a point on the curve into the compressed form
+// specified in section 4.3.6 of ANSI X9.62.
+func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
+ byteLen := (curve.Params().BitSize + 7) / 8
+ compressed := make([]byte, 1+byteLen)
+ compressed[0] = byte(y.Bit(0)) | 2
+ x.FillBytes(compressed[1:])
+ return compressed
+}
+
// Unmarshal converts a point, serialized by Marshal, into an x, y pair.
// It is an error if the point is not in uncompressed form or is not on the curve.
// On error, x = nil.
func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
byteLen := (curve.Params().BitSize + 7) / 8
if len(data) != 1+2*byteLen {
- return
+ return nil, nil
}
if data[0] != 4 { // uncompressed form
- return
+ return nil, nil
}
p := curve.Params().P
x = new(big.Int).SetBytes(data[1 : 1+byteLen])
@@ -338,6 +357,37 @@ func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
return
}
+// UnmarshalCompressed converts a point, serialized by MarshalCompressed, into an x, y pair.
+// It is an error if the point is not in compressed form or is not on the curve.
+// On error, x = nil.
+func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) {
+ byteLen := (curve.Params().BitSize + 7) / 8
+ if len(data) != 1+byteLen {
+ return nil, nil
+ }
+ if data[0] != 2 && data[0] != 3 { // compressed form
+ return nil, nil
+ }
+ p := curve.Params().P
+ x = new(big.Int).SetBytes(data[1:])
+ if x.Cmp(p) >= 0 {
+ return nil, nil
+ }
+ // y² = x³ - 3x + b
+ y = curve.Params().polynomial(x)
+ y = y.ModSqrt(y, p)
+ if y == nil {
+ return nil, nil
+ }
+ if byte(y.Bit(0)) != data[0]&1 {
+ y.Neg(y).Mod(y, p)
+ }
+ if !curve.IsOnCurve(x, y) {
+ return nil, nil
+ }
+ return
+}
+
var initonce sync.Once
var p384 *CurveParams
var p521 *CurveParams
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
index 09c5483520..e80e7731aa 100644
--- a/src/crypto/elliptic/elliptic_test.go
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -5,6 +5,7 @@
package elliptic
import (
+ "bytes"
"crypto/rand"
"encoding/hex"
"fmt"
@@ -417,41 +418,62 @@ func TestP256Mult(t *testing.T) {
}
}
-func TestInfinity(t *testing.T) {
- tests := []struct {
- name string
- curve Curve
- }{
- {"p224", P224()},
- {"p256", P256()},
+func testInfinity(t *testing.T, curve Curve) {
+ _, x, y, _ := GenerateKey(curve, rand.Reader)
+ x, y = curve.ScalarMult(x, y, curve.Params().N.Bytes())
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("x^q != ∞")
}
- for _, test := range tests {
- curve := test.curve
- x, y := curve.ScalarBaseMult(nil)
- if x.Sign() != 0 || y.Sign() != 0 {
- t.Errorf("%s: x^0 != ∞", test.name)
- }
+ x, y = curve.ScalarBaseMult([]byte{0})
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("b^0 != ∞")
x.SetInt64(0)
y.SetInt64(0)
+ }
- x2, y2 := curve.Double(x, y)
- if x2.Sign() != 0 || y2.Sign() != 0 {
- t.Errorf("%s: 2∞ != ∞", test.name)
- }
+ x2, y2 := curve.Double(x, y)
+ if x2.Sign() != 0 || y2.Sign() != 0 {
+ t.Errorf("2∞ != ∞")
+ }
- baseX := curve.Params().Gx
- baseY := curve.Params().Gy
+ baseX := curve.Params().Gx
+ baseY := curve.Params().Gy
- x3, y3 := curve.Add(baseX, baseY, x, y)
- if x3.Cmp(baseX) != 0 || y3.Cmp(baseY) != 0 {
- t.Errorf("%s: x+∞ != x", test.name)
- }
+ x3, y3 := curve.Add(baseX, baseY, x, y)
+ if x3.Cmp(baseX) != 0 || y3.Cmp(baseY) != 0 {
+ t.Errorf("x+∞ != x")
+ }
- x4, y4 := curve.Add(x, y, baseX, baseY)
- if x4.Cmp(baseX) != 0 || y4.Cmp(baseY) != 0 {
- t.Errorf("%s: ∞+x != x", test.name)
- }
+ x4, y4 := curve.Add(x, y, baseX, baseY)
+ if x4.Cmp(baseX) != 0 || y4.Cmp(baseY) != 0 {
+ t.Errorf("∞+x != x")
+ }
+
+ if curve.IsOnCurve(x, y) {
+ t.Errorf("IsOnCurve(∞) == true")
+ }
+}
+
+func TestInfinity(t *testing.T) {
+ tests := []struct {
+ name string
+ curve Curve
+ }{
+ {"P-224", P224()},
+ {"P-256", P256()},
+ {"P-256/Generic", P256().Params()},
+ {"P-384", P384()},
+ {"P-521", P521()},
+ }
+ if testing.Short() {
+ tests = tests[:1]
+ }
+ for _, test := range tests {
+ curve := test.curve
+ t.Run(test.name, func(t *testing.T) {
+ testInfinity(t, curve)
+ })
}
}
@@ -628,3 +650,74 @@ func TestUnmarshalToLargeCoordinates(t *testing.T) {
t.Errorf("Unmarshal accepts invalid Y coordinate")
}
}
+
+func TestMarshalCompressed(t *testing.T) {
+ t.Run("P-256/03", func(t *testing.T) {
+ data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
+ x, _ := new(big.Int).SetString("13671033352574878777044637384712060483119675368076128232297328793087057702265", 10)
+ y, _ := new(big.Int).SetString("66200849279091436748794323380043701364391950689352563629885086590854940586447", 10)
+ testMarshalCompressed(t, P256(), x, y, data)
+ })
+ t.Run("P-256/02", func(t *testing.T) {
+ data, _ := hex.DecodeString("021e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
+ x, _ := new(big.Int).SetString("13671033352574878777044637384712060483119675368076128232297328793087057702265", 10)
+ y, _ := new(big.Int).SetString("49591239931264812013903123569363872165694192725937750565648544718012157267504", 10)
+ testMarshalCompressed(t, P256(), x, y, data)
+ })
+
+ t.Run("Invalid", func(t *testing.T) {
+ data, _ := hex.DecodeString("02fd4bf61763b46581fd9174d623516cf3c81edd40e29ffa2777fb6cb0ae3ce535")
+ X, Y := UnmarshalCompressed(P256(), data)
+ if X != nil || Y != nil {
+ t.Error("expected an error for invalid encoding")
+ }
+ })
+
+ if testing.Short() {
+ t.Skip("skipping other curves on short test")
+ }
+
+ t.Run("P-224", func(t *testing.T) {
+ _, x, y, err := GenerateKey(P224(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testMarshalCompressed(t, P224(), x, y, nil)
+ })
+ t.Run("P-384", func(t *testing.T) {
+ _, x, y, err := GenerateKey(P384(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testMarshalCompressed(t, P384(), x, y, nil)
+ })
+ t.Run("P-521", func(t *testing.T) {
+ _, x, y, err := GenerateKey(P521(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testMarshalCompressed(t, P521(), x, y, nil)
+ })
+}
+
+func testMarshalCompressed(t *testing.T, curve Curve, x, y *big.Int, want []byte) {
+ if !curve.IsOnCurve(x, y) {
+ t.Fatal("invalid test point")
+ }
+ got := MarshalCompressed(curve, x, y)
+ if want != nil && !bytes.Equal(got, want) {
+ t.Errorf("got unexpected MarshalCompressed result: got %x, want %x", got, want)
+ }
+
+ X, Y := UnmarshalCompressed(curve, got)
+ if X == nil || Y == nil {
+ t.Fatalf("UnmarshalCompressed failed unexpectedly")
+ }
+
+ if !curve.IsOnCurve(X, Y) {
+ t.Error("UnmarshalCompressed returned a point not on the curve")
+ }
+ if X.Cmp(x) != 0 || Y.Cmp(y) != 0 {
+ t.Errorf("point did not round-trip correctly: got (%v, %v), want (%v, %v)", X, Y, x, y)
+ }
+}
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
index 52885b0760..2c4fc2db91 100644
--- a/src/crypto/hmac/hmac.go
+++ b/src/crypto/hmac/hmac.go
@@ -36,18 +36,36 @@ import "crypto/internal/boring"
// opad = 0x5c byte repeated for key length
// hmac = H([key ^ opad] H([key ^ ipad] text))
+// Marshalable is the combination of encoding.BinaryMarshaler and
+// encoding.BinaryUnmarshaler. Their method definitions are repeated here to
+// avoid a dependency on the encoding package.
+type marshalable interface {
+ MarshalBinary() ([]byte, error)
+ UnmarshalBinary([]byte) error
+}
+
type hmac struct {
- size int
- blocksize int
opad, ipad []byte
outer, inner hash.Hash
+
+ // If marshaled is true, then opad and ipad do not contain a padded
+ // copy of the key, but rather the marshaled state of outer/inner after
+ // opad/ipad has been fed into it.
+ marshaled bool
}
func (h *hmac) Sum(in []byte) []byte {
origLen := len(in)
in = h.inner.Sum(in)
- h.outer.Reset()
- h.outer.Write(h.opad)
+
+ if h.marshaled {
+ if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
+ panic(err)
+ }
+ } else {
+ h.outer.Reset()
+ h.outer.Write(h.opad)
+ }
h.outer.Write(in[origLen:])
return h.outer.Sum(in[:origLen])
}
@@ -56,13 +74,51 @@ func (h *hmac) Write(p []byte) (n int, err error) {
return h.inner.Write(p)
}
-func (h *hmac) Size() int { return h.size }
-
-func (h *hmac) BlockSize() int { return h.blocksize }
+func (h *hmac) Size() int { return h.outer.Size() }
+func (h *hmac) BlockSize() int { return h.inner.BlockSize() }
func (h *hmac) Reset() {
+ if h.marshaled {
+ if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
+ panic(err)
+ }
+ return
+ }
+
h.inner.Reset()
h.inner.Write(h.ipad)
+
+ // If the underlying hash is marshalable, we can save some time by
+ // saving a copy of the hash state now, and restoring it on future
+ // calls to Reset and Sum instead of writing ipad/opad every time.
+ //
+ // If either hash is unmarshalable for whatever reason,
+ // it's safe to bail out here.
+ marshalableInner, innerOK := h.inner.(marshalable)
+ if !innerOK {
+ return
+ }
+ marshalableOuter, outerOK := h.outer.(marshalable)
+ if !outerOK {
+ return
+ }
+
+ imarshal, err := marshalableInner.MarshalBinary()
+ if err != nil {
+ return
+ }
+
+ h.outer.Reset()
+ h.outer.Write(h.opad)
+ omarshal, err := marshalableOuter.MarshalBinary()
+ if err != nil {
+ return
+ }
+
+ // Marshaling succeeded; save the marshaled state for later
+ h.ipad = imarshal
+ h.opad = omarshal
+ h.marshaled = true
}
// New returns a new HMAC hash using the given hash.Hash type and key.
@@ -80,11 +136,10 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
hm := new(hmac)
hm.outer = h()
hm.inner = h()
- hm.size = hm.inner.Size()
- hm.blocksize = hm.inner.BlockSize()
- hm.ipad = make([]byte, hm.blocksize)
- hm.opad = make([]byte, hm.blocksize)
- if len(key) > hm.blocksize {
+ blocksize := hm.inner.BlockSize()
+ hm.ipad = make([]byte, blocksize)
+ hm.opad = make([]byte, blocksize)
+ if len(key) > blocksize {
// If key is too big, hash it.
hm.outer.Write(key)
key = hm.outer.Sum(nil)
@@ -98,6 +153,7 @@ func New(h func() hash.Hash, key []byte) hash.Hash {
hm.opad[i] ^= 0x5c
}
hm.inner.Write(hm.ipad)
+
return hm
}
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
index 96e84f74a1..7be8b1bbcf 100644
--- a/src/crypto/hmac/hmac_test.go
+++ b/src/crypto/hmac/hmac_test.go
@@ -555,7 +555,7 @@ func TestHMAC(t *testing.T) {
if b := h.BlockSize(); b != tt.blocksize {
t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
}
- for j := 0; j < 2; j++ {
+ for j := 0; j < 4; j++ {
n, err := h.Write(tt.in)
if n != len(tt.in) || err != nil {
t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
@@ -572,10 +572,21 @@ func TestHMAC(t *testing.T) {
// Second iteration: make sure reset works.
h.Reset()
+
+ // Third and fourth iteration: make sure hmac works on
+ // hashes without MarshalBinary/UnmarshalBinary
+ if j == 1 {
+ h = New(func() hash.Hash { return justHash{tt.hash()} }, tt.key)
+ }
}
}
}
+// justHash implements just the hash.Hash methods and nothing else
+type justHash struct {
+ hash.Hash
+}
+
func TestEqual(t *testing.T) {
a := []byte("test")
b := []byte("test1")
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
index f6fe2d2a90..30755bdd6f 100644
--- a/src/crypto/tls/common.go
+++ b/src/crypto/tls/common.go
@@ -213,28 +213,72 @@ var testingOnlyForceDowngradeCanary bool
// ConnectionState records basic TLS details about the connection.
type ConnectionState struct {
- Version uint16 // TLS version used by the connection (e.g. VersionTLS12)
- HandshakeComplete bool // TLS handshake is complete
- DidResume bool // connection resumes a previous TLS connection
- CipherSuite uint16 // cipher suite in use (TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, ...)
- NegotiatedProtocol string // negotiated next protocol (not guaranteed to be from Config.NextProtos)
- NegotiatedProtocolIsMutual bool // negotiated protocol was advertised by server (client side only)
- ServerName string // server name requested by client, if any (server side only)
- PeerCertificates []*x509.Certificate // certificate chain presented by remote peer
- VerifiedChains [][]*x509.Certificate // verified chains built from PeerCertificates
- SignedCertificateTimestamps [][]byte // SCTs from the peer, if any
- OCSPResponse []byte // stapled OCSP response from peer, if any
+ // Version is the TLS version used by the connection (e.g. VersionTLS12).
+ Version uint16
- // ekm is a closure exposed via ExportKeyingMaterial.
- ekm func(label string, context []byte, length int) ([]byte, error)
+ // HandshakeComplete is true if the handshake has concluded.
+ HandshakeComplete bool
+
+ // DidResume is true if this connection was successfully resumed from a
+ // previous session with a session ticket or similar mechanism.
+ DidResume bool
+
+ // CipherSuite is the cipher suite negotiated for the connection (e.g.
+ // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+ CipherSuite uint16
+
+ // NegotiatedProtocol is the application protocol negotiated with ALPN.
+ //
+ // Note that on the client side, this is currently not guaranteed to be from
+ // Config.NextProtos.
+ NegotiatedProtocol string
+
+ // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+ //
+ // Deprecated: this value is always true.
+ NegotiatedProtocolIsMutual bool
+
+ // ServerName is the value of the Server Name Indication extension sent by
+ // the client. It's available both on the server and on the client side.
+ ServerName string
+
+ // PeerCertificates are the parsed certificates sent by the peer, in the
+ // order in which they were sent. The first element is the leaf certificate
+ // that the connection is verified against.
+ //
+ // On the client side, it can't be empty. On the server side, it can be
+ // empty if Config.ClientAuth is not RequireAnyClientCert or
+ // RequireAndVerifyClientCert.
+ PeerCertificates []*x509.Certificate
+
+ // VerifiedChains is a list of one or more chains where the first element is
+ // PeerCertificates[0] and the last element is from Config.RootCAs (on the
+ // client side) or Config.ClientCAs (on the server side).
+ //
+ // On the client side, it's set if Config.InsecureSkipVerify is false. On
+ // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+ // (and the peer provided a certificate) or RequireAndVerifyClientCert.
+ VerifiedChains [][]*x509.Certificate
+
+ // SignedCertificateTimestamps is a list of SCTs provided by the peer
+ // through the TLS handshake for the leaf certificate, if any.
+ SignedCertificateTimestamps [][]byte
+
+ // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP)
+ // response provided by the peer for the leaf certificate, if any.
+ OCSPResponse []byte
- // TLSUnique contains the "tls-unique" channel binding value (see RFC
- // 5929, section 3). For resumed sessions this value will be nil
- // because resumption does not include enough context (see
- // https://mitls.org/pages/attacks/3SHAKE#channelbindings). This will
- // change in future versions of Go once the TLS master-secret fix has
- // been standardized and implemented. It is not defined in TLS 1.3.
+ // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+ // Section 3). This value will be nil for TLS 1.3 connections and for all
+ // resumed connections.
+ //
+ // Deprecated: there are conditions in which this value might not be unique
+ // to a connection. See the Security Considerations sections of RFC 5705 and
+ // RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
TLSUnique []byte
+
+ // ekm is a closure exposed via ExportKeyingMaterial.
+ ekm func(label string, context []byte, length int) ([]byte, error)
}
// ExportKeyingMaterial returns length bytes of exported key material in a new
@@ -278,6 +322,8 @@ type ClientSessionState struct {
serverCertificates []*x509.Certificate // Certificate chain presented by the server
verifiedChains [][]*x509.Certificate // Certificate chains we built for verification
receivedAt time.Time // When the session ticket was received from the server
+ ocspResponse []byte // Stapled OCSP response presented by the server
+ scts [][]byte // SCTs presented by the server
// TLS 1.3 fields.
nonce []byte // Ticket nonce sent by the server, to derive PSK
@@ -501,15 +547,10 @@ type Config struct {
// If GetConfigForClient is nil, the Config passed to Server() will be
// used for all connections.
//
- // Uniquely for the fields in the returned Config, session ticket keys
- // will be duplicated from the original Config if not set.
- // Specifically, if SetSessionTicketKeys was called on the original
- // config but not on the returned config then the ticket keys from the
- // original config will be copied into the new config before use.
- // Otherwise, if SessionTicketKey was set in the original config but
- // not in the returned config then it will be copied into the returned
- // config before use. If neither of those cases applies then the key
- // material from the returned config will be used for session tickets.
+ // If SessionTicketKey was explicitly set on the returned Config, or if
+ // SetSessionTicketKeys was called on the returned Config, those keys will
+ // be used. Otherwise, the original Config keys will be used (and possibly
+ // rotated if they are automatically managed).
GetConfigForClient func(*ClientHelloInfo) (*Config, error)
// VerifyPeerCertificate, if not nil, is called after normal
@@ -525,6 +566,16 @@ type Config struct {
// be considered but the verifiedChains argument will always be nil.
VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+ // VerifyConnection, if not nil, is called after normal certificate
+ // verification and after VerifyPeerCertificate by either a TLS client
+ // or server. If it returns a non-nil error, the handshake is aborted
+ // and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. This callback will run for all connections
+ // regardless of InsecureSkipVerify or ClientAuth settings.
+ VerifyConnection func(ConnectionState) error
+
// RootCAs defines the set of root certificate authorities
// that clients use when verifying server certificates.
// If RootCAs is nil, TLS uses the host's root CA set.
@@ -579,10 +630,10 @@ type Config struct {
// See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
// with random data before the first server handshake.
//
- // If multiple servers are terminating connections for the same host
- // they should all have the same SessionTicketKey. If the
- // SessionTicketKey leaks, previously recorded and future TLS
- // connections using that key might be compromised.
+ // Deprecated: if this field is left at zero, session ticket keys will be
+ // automatically rotated every day and dropped after seven days. For
+ // customizing the rotation schedule or synchronizing servers that are
+ // terminating connections for the same host, use SetSessionTicketKeys.
SessionTicketKey [32]byte
// ClientSessionCache is a cache of ClientSessionState entries for TLS
@@ -622,20 +673,32 @@ type Config struct {
// used for debugging.
KeyLogWriter io.Writer
- serverInitOnce sync.Once // guards calling (*Config).serverInit
-
- // mutex protects sessionTicketKeys.
+ // mutex protects sessionTicketKeys and autoSessionTicketKeys.
mutex sync.RWMutex
- // sessionTicketKeys contains zero or more ticket keys. If the length
- // is zero, SessionTicketsDisabled must be true. The first key is used
- // for new tickets and any subsequent keys can be used to decrypt old
- // tickets.
+ // sessionTicketKeys contains zero or more ticket keys. If set, it means the
+ // the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+ // first key is used for new tickets and any subsequent keys can be used to
+ // decrypt old tickets. The slice contents are not protected by the mutex
+ // and are immutable.
sessionTicketKeys []ticketKey
+ // autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+ // auto-rotation logic. See Config.ticketKeys.
+ autoSessionTicketKeys []ticketKey
}
-// ticketKeyNameLen is the number of bytes of identifier that is prepended to
-// an encrypted session ticket in order to identify the key used to encrypt it.
-const ticketKeyNameLen = 16
+const (
+ // ticketKeyNameLen is the number of bytes of identifier that is prepended to
+ // an encrypted session ticket in order to identify the key used to encrypt it.
+ ticketKeyNameLen = 16
+
+ // ticketKeyLifetime is how long a ticket key remains valid and can be used to
+ // resume a client connection.
+ ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+
+ // ticketKeyRotation is how often the server should rotate the session ticket key
+ // that is used for new tickets.
+ ticketKeyRotation = 24 * time.Hour
+)
// ticketKey is the internal representation of a session ticket key.
type ticketKey struct {
@@ -644,16 +707,19 @@ type ticketKey struct {
keyName [ticketKeyNameLen]byte
aesKey [16]byte
hmacKey [16]byte
+ // created is the time at which this ticket key was created. See Config.ticketKeys.
+ created time.Time
}
// ticketKeyFromBytes converts from the external representation of a session
// ticket key to a ticketKey. Externally, session ticket keys are 32 random
// bytes and this function expands that into sufficient name and key material.
-func ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
hashed := sha512.Sum512(b[:])
copy(key.keyName[:], hashed[:ticketKeyNameLen])
copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+ key.created = c.time()
return key
}
@@ -664,15 +730,8 @@ const maxSessionTicketLifetime = 7 * 24 * time.Hour
// Clone returns a shallow clone of c. It is safe to clone a Config that is
// being used concurrently by a TLS client or server.
func (c *Config) Clone() *Config {
- // Running serverInit ensures that it's safe to read
- // SessionTicketsDisabled.
- c.serverInitOnce.Do(func() { c.serverInit(nil) })
-
- var sessionTicketKeys []ticketKey
c.mutex.RLock()
- sessionTicketKeys = c.sessionTicketKeys
- c.mutex.RUnlock()
-
+ defer c.mutex.RUnlock()
return &Config{
Rand: c.Rand,
Time: c.Time,
@@ -682,6 +741,7 @@ func (c *Config) Clone() *Config {
GetClientCertificate: c.GetClientCertificate,
GetConfigForClient: c.GetConfigForClient,
VerifyPeerCertificate: c.VerifyPeerCertificate,
+ VerifyConnection: c.VerifyConnection,
RootCAs: c.RootCAs,
NextProtos: c.NextProtos,
ServerName: c.ServerName,
@@ -699,58 +759,122 @@ func (c *Config) Clone() *Config {
DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
Renegotiation: c.Renegotiation,
KeyLogWriter: c.KeyLogWriter,
- sessionTicketKeys: sessionTicketKeys,
+ sessionTicketKeys: c.sessionTicketKeys,
+ autoSessionTicketKeys: c.autoSessionTicketKeys,
}
}
-// serverInit is run under c.serverInitOnce to do initialization of c. If c was
-// returned by a GetConfigForClient callback then the argument should be the
-// Config that was passed to Server, otherwise it should be nil.
-func (c *Config) serverInit(originalConfig *Config) {
- if c.SessionTicketsDisabled || len(c.ticketKeys()) != 0 {
+// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was
+// randomized for backwards compatibility but is not in use.
+var deprecatedSessionTicketKey = []byte("DEPRECATED")
+
+// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is
+// randomized if empty, and that sessionTicketKeys is populated from it otherwise.
+func (c *Config) initLegacySessionTicketKeyRLocked() {
+ // Don't write if SessionTicketKey is already defined as our deprecated string,
+ // or if it is defined by the user but sessionTicketKeys is already set.
+ if c.SessionTicketKey != [32]byte{} &&
+ (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
return
}
- alreadySet := false
- for _, b := range c.SessionTicketKey {
- if b != 0 {
- alreadySet = true
- break
+ // We need to write some data, so get an exclusive lock and re-check any conditions.
+ c.mutex.RUnlock()
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ if c.SessionTicketKey == [32]byte{} {
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
}
+ // Write the deprecated prefix at the beginning so we know we created
+ // it. This key with the DEPRECATED prefix isn't used as an actual
+ // session ticket key, and is only randomized in case the application
+ // reuses it for some reason.
+ copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
+ } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
+ c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
}
- if !alreadySet {
- if originalConfig != nil {
- copy(c.SessionTicketKey[:], originalConfig.SessionTicketKey[:])
- } else if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
- c.SessionTicketsDisabled = true
- return
+}
+
+// ticketKeys returns the ticketKeys for this connection.
+// If configForClient has explicitly set keys, those will
+// be returned. Otherwise, the keys on c will be used and
+// may be rotated if auto-managed.
+// During rotation, any expired session ticket keys are deleted from
+// c.sessionTicketKeys. If the session ticket key that is currently
+// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys)
+// is not fresh, then a new session ticket key will be
+// created and prepended to c.sessionTicketKeys.
+func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
+ // If the ConfigForClient callback returned a Config with explicitly set
+ // keys, use those, otherwise just use the original Config.
+ if configForClient != nil {
+ configForClient.mutex.RLock()
+ if configForClient.SessionTicketsDisabled {
+ return nil
}
+ configForClient.initLegacySessionTicketKeyRLocked()
+ if len(configForClient.sessionTicketKeys) != 0 {
+ ret := configForClient.sessionTicketKeys
+ configForClient.mutex.RUnlock()
+ return ret
+ }
+ configForClient.mutex.RUnlock()
}
- if originalConfig != nil {
- originalConfig.mutex.RLock()
- c.sessionTicketKeys = originalConfig.sessionTicketKeys
- originalConfig.mutex.RUnlock()
- } else {
- c.sessionTicketKeys = []ticketKey{ticketKeyFromBytes(c.SessionTicketKey)}
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ if c.SessionTicketsDisabled {
+ return nil
+ }
+ c.initLegacySessionTicketKeyRLocked()
+ if len(c.sessionTicketKeys) != 0 {
+ return c.sessionTicketKeys
+ }
+ // Fast path for the common case where the key is fresh enough.
+ if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
+ return c.autoSessionTicketKeys
}
-}
-func (c *Config) ticketKeys() []ticketKey {
- c.mutex.RLock()
- // c.sessionTicketKeys is constant once created. SetSessionTicketKeys
- // will only update it by replacing it with a new value.
- ret := c.sessionTicketKeys
+ // autoSessionTicketKeys are managed by auto-rotation.
c.mutex.RUnlock()
- return ret
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ // Re-check the condition in case it changed since obtaining the new lock.
+ if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
+ var newKey [32]byte
+ if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
+ panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
+ }
+ valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
+ valid = append(valid, c.ticketKeyFromBytes(newKey))
+ for _, k := range c.autoSessionTicketKeys {
+ // While rotating the current key, also remove any expired ones.
+ if c.time().Sub(k.created) < ticketKeyLifetime {
+ valid = append(valid, k)
+ }
+ }
+ c.autoSessionTicketKeys = valid
+ }
+ return c.autoSessionTicketKeys
}
-// SetSessionTicketKeys updates the session ticket keys for a server. The first
-// key will be used when creating new tickets, while all keys can be used for
-// decrypting tickets. It is safe to call this function while the server is
-// running in order to rotate the session ticket keys. The function will panic
-// if keys is empty.
+// SetSessionTicketKeys updates the session ticket keys for a server.
+//
+// The first key will be used when creating new tickets, while all keys can be
+// used for decrypting tickets. It is safe to call this function while the
+// server is running in order to rotate the session ticket keys. The function
+// will panic if keys is empty.
+//
+// Calling this function will turn off automatic session ticket key rotation.
+//
+// If multiple servers are terminating connections for the same host they should
+// all have the same session ticket keys. If the session ticket keys leaks,
+// previously recorded and future TLS connections using those keys might be
+// compromised.
func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
if len(keys) == 0 {
panic("tls: keys must have at least one key")
@@ -758,7 +882,7 @@ func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
newKeys := make([]ticketKey, len(keys))
for i, bytes := range keys {
- newKeys[i] = ticketKeyFromBytes(bytes)
+ newKeys[i] = c.ticketKeyFromBytes(bytes)
}
c.mutex.Lock()
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
index bf2111cb97..edcfecf81d 100644
--- a/src/crypto/tls/conn.go
+++ b/src/crypto/tls/conn.go
@@ -62,6 +62,11 @@ type Conn struct {
// NewSessionTicket messages. nil if config.SessionTicketsDisabled.
resumptionSecret []byte
+ // ticketKeys is the set of active session ticket keys for this
+ // connection. The first one is used to encrypt new tickets and
+ // all are tried to decrypt tickets.
+ ticketKeys []ticketKey
+
// clientFinishedIsFirst is true if the client sent the first Finished
// message during the most recent handshake. This is recorded because
// the first transmitted Finished message is the tls-unique
@@ -1374,35 +1379,34 @@ func (c *Conn) Handshake() error {
func (c *Conn) ConnectionState() ConnectionState {
c.handshakeMutex.Lock()
defer c.handshakeMutex.Unlock()
+ return c.connectionStateLocked()
+}
+func (c *Conn) connectionStateLocked() ConnectionState {
var state ConnectionState
state.HandshakeComplete = c.handshakeComplete()
+ state.Version = c.vers
+ state.NegotiatedProtocol = c.clientProtocol
+ state.DidResume = c.didResume
+ state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
state.ServerName = c.serverName
-
- if state.HandshakeComplete {
- state.Version = c.vers
- state.NegotiatedProtocol = c.clientProtocol
- state.DidResume = c.didResume
- state.NegotiatedProtocolIsMutual = !c.clientProtocolFallback
- state.CipherSuite = c.cipherSuite
- state.PeerCertificates = c.peerCertificates
- state.VerifiedChains = c.verifiedChains
- state.SignedCertificateTimestamps = c.scts
- state.OCSPResponse = c.ocspResponse
- if !c.didResume && c.vers != VersionTLS13 {
- if c.clientFinishedIsFirst {
- state.TLSUnique = c.clientFinished[:]
- } else {
- state.TLSUnique = c.serverFinished[:]
- }
- }
- if c.config.Renegotiation != RenegotiateNever {
- state.ekm = noExportedKeyingMaterial
+ state.CipherSuite = c.cipherSuite
+ state.PeerCertificates = c.peerCertificates
+ state.VerifiedChains = c.verifiedChains
+ state.SignedCertificateTimestamps = c.scts
+ state.OCSPResponse = c.ocspResponse
+ if !c.didResume && c.vers != VersionTLS13 {
+ if c.clientFinishedIsFirst {
+ state.TLSUnique = c.clientFinished[:]
} else {
- state.ekm = c.ekm
+ state.TLSUnique = c.serverFinished[:]
}
}
-
+ if c.config.Renegotiation != RenegotiateNever {
+ state.ekm = noExportedKeyingMaterial
+ } else {
+ state.ekm = c.ekm
+ }
return state
}
diff --git a/src/crypto/tls/example_test.go b/src/crypto/tls/example_test.go
index cf58a58a8a..6389fd7fed 100644
--- a/src/crypto/tls/example_test.go
+++ b/src/crypto/tls/example_test.go
@@ -7,7 +7,6 @@ package tls_test
import (
"crypto/tls"
"crypto/x509"
- "errors"
"log"
"net/http"
"net/http/httptest"
@@ -184,54 +183,50 @@ EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
log.Fatal(srv.ListenAndServeTLS("", ""))
}
-func ExampleConfig_verifyPeerCertificate() {
- // VerifyPeerCertificate can be used to replace and customize certificate
- // verification. This example shows a VerifyPeerCertificate implementation
- // that will be approximately equivalent to what crypto/tls does normally.
+func ExampleConfig_verifyConnection() {
+ // VerifyConnection can be used to replace and customize connection
+ // verification. This example shows a VerifyConnection implementation that
+ // will be approximately equivalent to what crypto/tls does normally to
+ // verify the peer's certificate.
- config := &tls.Config{
+ // Client side configuration.
+ _ = &tls.Config{
// Set InsecureSkipVerify to skip the default validation we are
- // replacing. This will not disable VerifyPeerCertificate.
+ // replacing. This will not disable VerifyConnection.
InsecureSkipVerify: true,
-
- // While packages like net/http will implicitly set ServerName, the
- // VerifyPeerCertificate callback can't access that value, so it has to be set
- // explicitly here or in VerifyPeerCertificate on the client side. If in
- // an http.Transport DialTLS callback, this can be obtained by passing
- // the addr argument to net.SplitHostPort.
- ServerName: "example.com",
-
- // On the server side, set ClientAuth to require client certificates (or
- // VerifyPeerCertificate will run anyway and panic accessing certs[0])
- // but not verify them with the default verifier.
- // ClientAuth: tls.RequireAnyClientCert,
+ VerifyConnection: func(cs tls.ConnectionState) error {
+ opts := x509.VerifyOptions{
+ DNSName: cs.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+ for _, cert := range cs.PeerCertificates[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err := cs.PeerCertificates[0].Verify(opts)
+ return err
+ },
}
- config.VerifyPeerCertificate = func(certificates [][]byte, _ [][]*x509.Certificate) error {
- certs := make([]*x509.Certificate, len(certificates))
- for i, asn1Data := range certificates {
- cert, err := x509.ParseCertificate(asn1Data)
- if err != nil {
- return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ // Server side configuration.
+ _ = &tls.Config{
+ // Require client certificates (or VerifyConnection will run anyway and
+ // panic accessing cs.PeerCertificates[0]) but don't verify them with the
+ // default verifier. This will not disable VerifyConnection.
+ ClientAuth: tls.RequireAnyClientCert,
+ VerifyConnection: func(cs tls.ConnectionState) error {
+ opts := x509.VerifyOptions{
+ DNSName: cs.ServerName,
+ Intermediates: x509.NewCertPool(),
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+ for _, cert := range cs.PeerCertificates[1:] {
+ opts.Intermediates.AddCert(cert)
}
- certs[i] = cert
- }
-
- opts := x509.VerifyOptions{
- Roots: config.RootCAs, // On the server side, use config.ClientCAs.
- DNSName: config.ServerName,
- Intermediates: x509.NewCertPool(),
- // On the server side, set KeyUsages to ExtKeyUsageClientAuth. The
- // default value is appropriate for clients side verification.
- // KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
- }
- for _, cert := range certs[1:] {
- opts.Intermediates.AddCert(cert)
- }
- _, err := certs[0].Verify(opts)
- return err
+ _, err := cs.PeerCertificates[0].Verify(opts)
+ return err
+ },
}
- // Note that when InsecureSkipVerify and VerifyPeerCertificate are in use,
+ // Note that when certificates are not handled by the default verifier
// ConnectionState.VerifiedChains will be nil.
}
diff --git a/src/crypto/tls/generate_cert.go b/src/crypto/tls/generate_cert.go
index f1d69c401a..1857185fe4 100644
--- a/src/crypto/tls/generate_cert.go
+++ b/src/crypto/tls/generate_cert.go
@@ -81,6 +81,16 @@ func main() {
log.Fatalf("Failed to generate private key: %v", err)
}
+ // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+ // KeyUsage bits set in the x509.Certificate template
+ keyUsage := x509.KeyUsageDigitalSignature
+ // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+ // the context of TLS this KeyUsage is particular to RSA key exchange and
+ // authentication.
+ if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+ keyUsage |= x509.KeyUsageKeyEncipherment
+ }
+
var notBefore time.Time
if len(*validFrom) == 0 {
notBefore = time.Now()
@@ -107,7 +117,7 @@ func main() {
NotBefore: notBefore,
NotAfter: notAfter,
- KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ KeyUsage: keyUsage,
ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
BasicConstraintsValid: true,
}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
index a72555f66e..e089762b9f 100644
--- a/src/crypto/tls/handshake_client.go
+++ b/src/crypto/tls/handshake_client.go
@@ -149,6 +149,7 @@ func (c *Conn) clientHandshake() (err error) {
if err != nil {
return err
}
+ c.serverName = hello.serverName
cacheKey, session, earlySecret, binderKey := c.loadSession(hello)
if cacheKey != "" && session != nil {
@@ -391,6 +392,7 @@ func (hs *clientHandshakeState) handshake() error {
hs.finishedHash.Write(hs.serverHello.marshal())
c.buffering = true
+ c.didResume = isResume
if isResume {
if err := hs.establishKeys(); err != nil {
return err
@@ -402,6 +404,15 @@ func (hs *clientHandshakeState) handshake() error {
return err
}
c.clientFinishedIsFirst = false
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
if err := hs.sendFinished(c.clientFinished[:]); err != nil {
return err
}
@@ -431,7 +442,6 @@ func (hs *clientHandshakeState) handshake() error {
}
c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
- c.didResume = isResume
atomic.StoreUint32(&c.handshakeStatus, 1)
return nil
@@ -461,25 +471,6 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
hs.finishedHash.Write(certMsg.marshal())
- if c.handshakes == 0 {
- // If this is the first handshake on a connection, process and
- // (optionally) verify the server's certificates.
- if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
- return err
- }
- } else {
- // This is a renegotiation handshake. We require that the
- // server's identity (i.e. leaf certificate) is unchanged and
- // thus any previous trust decision is still valid.
- //
- // See https://mitls.org/pages/attacks/3SHAKE for the
- // motivation behind this requirement.
- if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
- c.sendAlert(alertBadCertificate)
- return errors.New("tls: server's identity changed during renegotiation")
- }
- }
-
msg, err = c.readHandshake()
if err != nil {
return err
@@ -508,6 +499,25 @@ func (hs *clientHandshakeState) doFullHandshake() error {
}
}
+ if c.handshakes == 0 {
+ // If this is the first handshake on a connection, process and
+ // (optionally) verify the server's certificates.
+ if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
+ return err
+ }
+ } else {
+ // This is a renegotiation handshake. We require that the
+ // server's identity (i.e. leaf certificate) is unchanged and
+ // thus any previous trust decision is still valid.
+ //
+ // See https://mitls.org/pages/attacks/3SHAKE for the
+ // motivation behind this requirement.
+ if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: server's identity changed during renegotiation")
+ }
+ }
+
keyAgreement := hs.suite.ka(c.vers)
skx, ok := msg.(*serverKeyExchangeMsg)
@@ -721,10 +731,17 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
return false, errors.New("tls: server resumed a session with a different cipher suite")
}
- // Restore masterSecret and peerCerts from previous state
+ // Restore masterSecret, peerCerts, and ocspResponse from previous state
hs.masterSecret = hs.session.masterSecret
c.peerCertificates = hs.session.serverCertificates
c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ // Let the ServerHello SCTs override the session SCTs from the original
+ // connection, if any are provided
+ if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+ c.scts = hs.session.scts
+ }
+
return true, nil
}
@@ -781,6 +798,8 @@ func (hs *clientHandshakeState) readSessionTicket() error {
serverCertificates: c.peerCertificates,
verifiedChains: c.verifiedChains,
receivedAt: c.config.time(),
+ ocspResponse: c.ocspResponse,
+ scts: c.scts,
}
return nil
@@ -836,13 +855,6 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
}
}
- if c.config.VerifyPeerCertificate != nil {
- if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
- c.sendAlert(alertBadCertificate)
- return err
- }
- }
-
switch certs[0].PublicKey.(type) {
case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
break
@@ -853,6 +865,20 @@ func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
c.peerCertificates = certs
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
return nil
}
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
index 35d7136fc6..12b0254123 100644
--- a/src/crypto/tls/handshake_client_test.go
+++ b/src/crypto/tls/handshake_client_test.go
@@ -19,6 +19,7 @@ import (
"os"
"os/exec"
"path/filepath"
+ "reflect"
"strconv"
"strings"
"testing"
@@ -907,6 +908,9 @@ func testResumption(t *testing.T, version uint16) {
if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifiedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
}
+ if got, want := hs.ServerName, clientConfig.ServerName; got != want {
+ t.Errorf("%s: server name %s, want %s", test, got, want)
+ }
}
getTicket := func() []byte {
@@ -937,6 +941,21 @@ func testResumption(t *testing.T, version uint16) {
t.Fatal("ticket didn't change after resumption")
}
+ // An old session ticket can resume, but the server will provide a ticket encrypted with a fresh key.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
+ testResumeState("ResumeWithOldTicket", true)
+ if bytes.Equal(ticket[:ticketKeyNameLen], getTicket()[:ticketKeyNameLen]) {
+ t.Fatal("old first ticket matches the fresh one")
+ }
+
+ // Now the session tickey key is expired, so a full handshake should occur.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
+ testResumeState("ResumeWithExpiredTicket", false)
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("expired first ticket matches the fresh one")
+ }
+
+ serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
key1 := randomKey()
serverConfig.SetSessionTicketKeys([][32]byte{key1})
@@ -952,6 +971,39 @@ func testResumption(t *testing.T, version uint16) {
}
testResumeState("KeyChangeFinish", true)
+ // Age the session ticket a bit, but not yet expired.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
+ testResumeState("OldSessionTicket", true)
+ ticket = getTicket()
+ // Expire the session ticket, which would force a full handshake.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
+ testResumeState("ExpiredSessionTicket", false)
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("new ticket wasn't provided after old ticket expired")
+ }
+
+ // Age the session ticket a bit at a time, but don't expire it.
+ d := 0 * time.Hour
+ for i := 0; i < 13; i++ {
+ d += 12 * time.Hour
+ serverConfig.Time = func() time.Time { return time.Now().Add(d) }
+ testResumeState("OldSessionTicket", true)
+ }
+ // Expire it (now a little more than 7 days) and make sure a full
+ // handshake occurs for TLS 1.2. Resumption should still occur for
+ // TLS 1.3 since the client should be using a fresh ticket sent over
+ // by the server.
+ d += 12 * time.Hour
+ serverConfig.Time = func() time.Time { return time.Now().Add(d) }
+ if version == VersionTLS13 {
+ testResumeState("ExpiredSessionTicket", true)
+ } else {
+ testResumeState("ExpiredSessionTicket", false)
+ }
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("new ticket wasn't provided after old ticket expired")
+ }
+
// Reset serverConfig to ensure that calling SetSessionTicketKeys
// before the serverConfig is used works.
serverConfig = &Config{
@@ -1413,6 +1465,228 @@ func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
}
}
+func TestVerifyConnection(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testVerifyConnection(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testVerifyConnection(t, VersionTLS13) })
+}
+
+func testVerifyConnection(t *testing.T, version uint16) {
+ checkFields := func(c ConnectionState, called *int, errorType string) error {
+ if c.Version != version {
+ return fmt.Errorf("%s: got Version %v, want %v", errorType, c.Version, version)
+ }
+ if c.HandshakeComplete {
+ return fmt.Errorf("%s: got HandshakeComplete, want false", errorType)
+ }
+ if c.ServerName != "example.golang" {
+ return fmt.Errorf("%s: got ServerName %s, want %s", errorType, c.ServerName, "example.golang")
+ }
+ if c.NegotiatedProtocol != "protocol1" {
+ return fmt.Errorf("%s: got NegotiatedProtocol %s, want %s", errorType, c.NegotiatedProtocol, "protocol1")
+ }
+ if c.CipherSuite == 0 {
+ return fmt.Errorf("%s: got CipherSuite 0, want non-zero", errorType)
+ }
+ wantDidResume := false
+ if *called == 2 { // if this is the second time, then it should be a resumption
+ wantDidResume = true
+ }
+ if c.DidResume != wantDidResume {
+ return fmt.Errorf("%s: got DidResume %t, want %t", errorType, c.DidResume, wantDidResume)
+ }
+ return nil
+ }
+
+ tests := []struct {
+ name string
+ configureServer func(*Config, *int)
+ configureClient func(*Config, *int)
+ }{
+ {
+ name: "RequireAndVerifyClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequireAndVerifyClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("server: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("server: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("client: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Responce are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "InsecureSkipVerify",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequireAnyClientCert
+ config.InsecureSkipVerify = true
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("server: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if c.VerifiedChains != nil {
+ return fmt.Errorf("server: got Verified Chains %v, want nil", c.VerifiedChains)
+ }
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.InsecureSkipVerify = true
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if c.VerifiedChains != nil {
+ return fmt.Errorf("server: got Verified Chains %v, want nil", c.VerifiedChains)
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Responce are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "NoClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = NoClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "RequestClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequestClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.Certificates = nil // clear the client cert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("client: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Responce are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ }
+ for _, test := range tests {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ var serverCalled, clientCalled int
+
+ serverConfig := &Config{
+ MaxVersion: version,
+ Certificates: []Certificate{testConfig.Certificates[0]},
+ ClientCAs: rootCAs,
+ NextProtos: []string{"protocol1"},
+ }
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
+ serverConfig.Certificates[0].OCSPStaple = []byte("dummy ocsp")
+ test.configureServer(serverConfig, &serverCalled)
+
+ clientConfig := &Config{
+ MaxVersion: version,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ RootCAs: rootCAs,
+ ServerName: "example.golang",
+ Certificates: []Certificate{testConfig.Certificates[0]},
+ NextProtos: []string{"protocol1"},
+ }
+ test.configureClient(clientConfig, &clientCalled)
+
+ testHandshakeState := func(name string, didResume bool) {
+ _, hs, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("%s: handshake failed: %s", name, err)
+ }
+ if hs.DidResume != didResume {
+ t.Errorf("%s: resumed: %v, expected: %v", name, hs.DidResume, didResume)
+ }
+ wantCalled := 1
+ if didResume {
+ wantCalled = 2 // resumption would mean this is the second time it was called in this test
+ }
+ if clientCalled != wantCalled {
+ t.Errorf("%s: expected client VerifyConnection called %d times, did %d times", name, wantCalled, clientCalled)
+ }
+ if serverCalled != wantCalled {
+ t.Errorf("%s: expected server VerifyConnection called %d times, did %d times", name, wantCalled, serverCalled)
+ }
+ }
+ testHandshakeState(fmt.Sprintf("%s-FullHandshake", test.name), false)
+ testHandshakeState(fmt.Sprintf("%s-Resumption", test.name), true)
+ }
+}
+
func TestVerifyPeerCertificate(t *testing.T) {
t.Run("TLSv12", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS12) })
t.Run("TLSv13", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS13) })
@@ -1431,7 +1705,7 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
sentinelErr := errors.New("TestVerifyPeerCertificate")
- verifyCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
if l := len(rawCerts); l != 1 {
return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
}
@@ -1441,6 +1715,19 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
*called = true
return nil
}
+ verifyConnectionCallback := func(called *bool, isClient bool, c ConnectionState) error {
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if isClient && len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ *called = true
+ return nil
+ }
tests := []struct {
configureServer func(*Config, *bool)
@@ -1451,13 +1738,13 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
configureServer: func(config *Config, called *bool) {
config.InsecureSkipVerify = false
config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
- return verifyCallback(called, rawCerts, validatedChains)
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
}
},
configureClient: func(config *Config, called *bool) {
config.InsecureSkipVerify = false
config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
- return verifyCallback(called, rawCerts, validatedChains)
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
}
},
validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
@@ -1538,6 +1825,116 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
}
},
},
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return verifyConnectionCallback(called, false, c)
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return verifyConnectionCallback(called, true, c)
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = nil
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = nil
+ config.VerifyConnection = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = nil
+ config.VerifyConnection = nil
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ },
+ },
}
for i, test := range tests {
@@ -1553,6 +1950,11 @@ func testVerifyPeerCertificate(t *testing.T, version uint16) {
config.ClientCAs = rootCAs
config.Time = now
config.MaxVersion = version
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ config.Certificates[0].PrivateKey = testRSAPrivateKey
+ config.Certificates[0].SignedCertificateTimestamps = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
+ config.Certificates[0].OCSPStaple = []byte("dummy ocsp")
test.configureServer(config, &serverCalled)
err = Server(s, config).Handshake()
@@ -2029,3 +2431,83 @@ func TestDowngradeCanary(t *testing.T) {
t.Errorf("client unexpectedly reacted to a canary in TLS 1.0")
}
}
+
+func TestResumptionKeepsOCSPAndSCT(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS13) })
+}
+
+func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ t.Fatalf("failed to parse test issuer")
+ }
+ roots := x509.NewCertPool()
+ roots.AddCert(issuer)
+ clientConfig := &Config{
+ MaxVersion: ver,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ ServerName: "example.golang",
+ RootCAs: roots,
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.MaxVersion = ver
+ serverConfig.Certificates[0].OCSPStaple = []byte{1, 2, 3}
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{4, 5, 6}}
+
+ _, ccs, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ // after a new session we expect to see OCSPResponse and
+ // SignedCertificateTimestamps populated as usual
+ if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
+ t.Errorf("client ConnectionState contained unexpected OCSPResponse: wanted %v, got %v",
+ serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps: wanted %v, got %v",
+ serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
+ }
+
+ // if the server doesn't send any SCTs, repopulate the old SCTs
+ oldSCTs := serverConfig.Certificates[0].SignedCertificateTimestamps
+ serverConfig.Certificates[0].SignedCertificateTimestamps = nil
+ _, ccs, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !ccs.DidResume {
+ t.Fatalf("expected session to be resumed")
+ }
+ // after a resumed session we also expect to see OCSPResponse
+ // and SignedCertificateTimestamps populated
+ if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
+ t.Errorf("client ConnectionState contained unexpected OCSPResponse after resumption: wanted %v, got %v",
+ serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, oldSCTs) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
+ oldSCTs, ccs.SignedCertificateTimestamps)
+ }
+
+ // Only test overriding the SCTs for TLS 1.2, since in 1.3
+ // the server won't send the message containing them
+ if ver == VersionTLS13 {
+ return
+ }
+
+ // if the server changes the SCTs it sends, they should override the saved SCTs
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{7, 8, 9}}
+ _, ccs, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !ccs.DidResume {
+ t.Fatalf("expected session to be resumed")
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
+ serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
+ }
+}
diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
index c454d7f9ac..fab26b246a 100644
--- a/src/crypto/tls/handshake_client_tls13.go
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -338,6 +338,8 @@ func (hs *clientHandshakeStateTLS13) processServerHello() error {
c.didResume = true
c.peerCertificates = hs.session.serverCertificates
c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ c.scts = hs.session.scts
return nil
}
@@ -411,6 +413,15 @@ func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
// Either a PSK or a certificate is always used, but not both.
// See RFC 8446, Section 4.1.1.
if hs.usingPSK {
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
return nil
}
@@ -661,6 +672,8 @@ func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
nonce: msg.nonce,
useBy: c.config.time().Add(lifetime),
ageAdd: msg.ageAdd,
+ ocspResponse: c.ocspResponse,
+ scts: c.scts,
}
cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
index 49fd42d8de..8821670e9a 100644
--- a/src/crypto/tls/handshake_messages_test.go
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -309,6 +309,7 @@ func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value {
s.vers = uint16(rand.Intn(10000))
s.cipherSuite = uint16(rand.Intn(10000))
s.masterSecret = randomBytes(rand.Intn(100)+1, rand)
+ s.createdAt = uint64(rand.Int63())
for i := 0; i < rand.Intn(20); i++ {
s.certificates = append(s.certificates, randomBytes(rand.Intn(500)+1, rand))
}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
index 0e0856c224..99e30b8845 100644
--- a/src/crypto/tls/handshake_server.go
+++ b/src/crypto/tls/handshake_server.go
@@ -15,6 +15,7 @@ import (
"fmt"
"io"
"sync/atomic"
+ "time"
)
// serverHandshakeState contains details of a server handshake in progress.
@@ -36,10 +37,6 @@ type serverHandshakeState struct {
// serverHandshake performs a TLS handshake as a server.
func (c *Conn) serverHandshake() error {
- // If this is the first server handshake, we generate a random key to
- // encrypt the tickets with.
- c.config.serverInitOnce.Do(func() { c.config.serverInit(nil) })
-
clientHello, err := c.readClientHello()
if err != nil {
return err
@@ -71,19 +68,15 @@ func (hs *serverHandshakeState) handshake() error {
c.buffering = true
if hs.checkForResumption() {
// The client has included a session ticket and so we do an abbreviated handshake.
+ c.didResume = true
if err := hs.doResumeHandshake(); err != nil {
return err
}
if err := hs.establishKeys(); err != nil {
return err
}
- // ticketSupported is set in a resumption handshake if the
- // ticket from the client was encrypted with an old session
- // ticket key and thus a refreshed ticket should be sent.
- if hs.hello.ticketSupported {
- if err := hs.sendSessionTicket(); err != nil {
- return err
- }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
}
if err := hs.sendFinished(c.serverFinished[:]); err != nil {
return err
@@ -95,7 +88,6 @@ func (hs *serverHandshakeState) handshake() error {
if err := hs.readFinished(nil); err != nil {
return err
}
- c.didResume = true
} else {
// The client didn't include a session ticket, or it wasn't
// valid so we do a full handshake.
@@ -142,16 +134,18 @@ func (c *Conn) readClientHello() (*clientHelloMsg, error) {
return nil, unexpectedMessageError(clientHello, msg)
}
+ var configForClient *Config
+ originalConfig := c.config
if c.config.GetConfigForClient != nil {
chi := clientHelloInfo(c, clientHello)
- if newConfig, err := c.config.GetConfigForClient(chi); err != nil {
+ if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
c.sendAlert(alertInternalError)
return nil, err
- } else if newConfig != nil {
- newConfig.serverInitOnce.Do(func() { newConfig.serverInit(c.config) })
- c.config = newConfig
+ } else if configForClient != nil {
+ c.config = configForClient
}
}
+ c.ticketKeys = originalConfig.ticketKeys(configForClient)
clientVersions := clientHello.supportedVersions
if len(clientHello.supportedVersions) == 0 {
@@ -314,6 +308,7 @@ func (hs *serverHandshakeState) pickCipherSuite() error {
c.sendAlert(alertHandshakeFailure)
return errors.New("tls: no cipher suite supported by both client and server")
}
+ c.cipherSuite = hs.suite.id
for _, id := range hs.clientHello.cipherSuites {
if id == TLS_FALLBACK_SCSV {
@@ -368,6 +363,11 @@ func (hs *serverHandshakeState) checkForResumption() bool {
return false
}
+ createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ return false
+ }
+
// Never resume a session for a different TLS version.
if c.vers != hs.sessionState.vers {
return false
@@ -408,6 +408,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
c := hs.c
hs.hello.cipherSuite = hs.suite.id
+ c.cipherSuite = hs.suite.id
// We echo the client's session ID in the ServerHello to let it know
// that we're doing a resumption.
hs.hello.sessionId = hs.clientHello.sessionId
@@ -426,6 +427,13 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
return err
}
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
hs.masterSecret = hs.sessionState.masterSecret
return nil
@@ -550,6 +558,12 @@ func (hs *serverHandshakeState) doFullHandshake() error {
return err
}
}
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
// Get client key exchange
ckx, ok := msg.(*clientKeyExchangeMsg)
@@ -675,6 +689,9 @@ func (hs *serverHandshakeState) readFinished(out []byte) error {
}
func (hs *serverHandshakeState) sendSessionTicket() error {
+ // ticketSupported is set in a resumption handshake if the
+ // ticket from the client was encrypted with an old session
+ // ticket key and thus a refreshed ticket should be sent.
if !hs.hello.ticketSupported {
return nil
}
@@ -682,6 +699,13 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
c := hs.c
m := new(newSessionTicketMsg)
+ createdAt := uint64(c.config.time().Unix())
+ if hs.sessionState != nil {
+ // If this is re-wrapping an old key, then keep
+ // the original time it was created.
+ createdAt = hs.sessionState.createdAt
+ }
+
var certsFromClient [][]byte
for _, cert := range c.peerCertificates {
certsFromClient = append(certsFromClient, cert.Raw)
@@ -689,6 +713,7 @@ func (hs *serverHandshakeState) sendSessionTicket() error {
state := sessionState{
vers: c.vers,
cipherSuite: hs.suite.id,
+ createdAt: createdAt,
masterSecret: hs.masterSecret,
certificates: certsFromClient,
}
@@ -720,7 +745,6 @@ func (hs *serverHandshakeState) sendFinished(out []byte) error {
return err
}
- c.cipherSuite = hs.suite.id
copy(out, finished.verifyData)
return nil
@@ -768,6 +792,19 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
c.verifiedChains = chains
}
+ c.peerCertificates = certs
+ c.ocspResponse = certificate.OCSPStaple
+ c.scts = certificate.SignedCertificateTimestamps
+
+ if len(certs) > 0 {
+ switch certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ }
+
if c.config.VerifyPeerCertificate != nil {
if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
c.sendAlert(alertBadCertificate)
@@ -775,20 +812,6 @@ func (c *Conn) processCertsFromClient(certificate Certificate) error {
}
}
- if len(certs) == 0 {
- return nil
- }
-
- switch certs[0].PublicKey.(type) {
- case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
- default:
- c.sendAlert(alertUnsupportedCertificate)
- return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
- }
-
- c.peerCertificates = certs
- c.ocspResponse = certificate.OCSPStaple
- c.scts = certificate.SignedCertificateTimestamps
return nil
}
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
index 61f0ca2bf7..a7a5324312 100644
--- a/src/crypto/tls/handshake_server_test.go
+++ b/src/crypto/tls/handshake_server_test.go
@@ -1496,12 +1496,8 @@ var getConfigForClientTests = []struct {
},
"",
func(config *Config) error {
- // The value of SessionTicketKey should have been
- // duplicated into the per-connection Config.
- for i := range config.SessionTicketKey {
- if b := config.SessionTicketKey[i]; b != byte(i) {
- return fmt.Errorf("SessionTicketKey was not duplicated from original Config: byte %d has value %d", i, b)
- }
+ if config.SessionTicketKey == [32]byte{} {
+ return fmt.Errorf("expected SessionTicketKey to be set")
}
return nil
},
@@ -1522,10 +1518,8 @@ var getConfigForClientTests = []struct {
},
"",
func(config *Config) error {
- // The session ticket keys should have been duplicated
- // into the per-connection Config.
- if l := len(config.sessionTicketKeys); l != 1 {
- return fmt.Errorf("got len(sessionTicketKeys) == %d, wanted 1", l)
+ if config.SessionTicketKey == [32]byte{} {
+ return fmt.Errorf("expected SessionTicketKey to be set")
}
return nil
},
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
index 95dd8a60ea..7a84efd2a9 100644
--- a/src/crypto/tls/handshake_server_tls13.go
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -310,6 +310,7 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
return errors.New("tls: invalid PSK binder")
}
+ c.didResume = true
if err := c.processCertsFromClient(sessionState.certificate); err != nil {
return err
}
@@ -317,7 +318,6 @@ func (hs *serverHandshakeStateTLS13) checkForResumption() error {
hs.hello.selectedIdentityPresent = true
hs.hello.selectedIdentity = uint16(i)
hs.usingPSK = true
- c.didResume = true
return nil
}
@@ -757,6 +757,14 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
c := hs.c
if !hs.requestClientCert() {
+ // Make sure the connection is still being verified whether or not
+ // the server requested a client certificate.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
return nil
}
@@ -779,6 +787,13 @@ func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
return err
}
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
if len(certMsg.certificate.Certificate) != 0 {
msg, err = c.readHandshake()
if err != nil {
diff --git a/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
index 5f80cb3595..a5d9ee4cdb 100644
--- a/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
+++ b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
@@ -1,12 +1,11 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 75 01 00 00 71 03 01 a0 fd 51 a6 77 |....u...q....Q.w|
-00000010 69 ee 39 14 8d 0f be a6 9c f7 95 aa 63 14 d2 90 |i.9.........c...|
-00000020 1e 39 34 2c df d8 e4 92 2b a0 36 00 00 12 c0 0a |.94,....+.6.....|
+00000000 16 03 01 00 63 01 00 00 5f 03 01 7a df fa af 20 |....c..._..z... |
+00000010 74 5a 83 3b 91 95 b4 9b 57 d8 6b f2 88 2a 68 e8 |tZ.;....W.k..*h.|
+00000020 b8 9e e7 88 a6 c5 e7 59 08 ff 9b 00 00 12 c0 0a |.......Y........|
00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..|
-00000040 01 00 00 36 00 00 00 0e 00 0c 00 00 09 31 32 37 |...6.........127|
-00000050 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 00 0a |.0.0.1..........|
-00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
-00000070 00 00 00 16 00 00 00 17 00 00 |..........|
+00000040 01 00 00 24 00 0b 00 04 03 00 01 02 00 0a 00 0c |...$............|
+00000050 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 00 00 |.............#..|
+00000060 00 16 00 00 00 17 00 00 |........|
>>> Flow 2 (server to client)
00000000 16 03 01 00 3b 02 00 00 37 03 01 00 00 00 00 00 |....;...7.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -52,43 +51,43 @@
00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
000002a0 01 00 aa 0c 00 00 a6 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
-000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 00 80 00 9f b3 |......_X.;t.....|
-000002d0 fa c1 71 14 e3 1a 6c 3f b6 61 15 e2 7b 99 c5 4c |..q...l?.a..{..L|
-000002e0 39 e0 45 f8 9d d3 84 1a c4 fc 7c 51 32 3d 67 0b |9.E.......|Q2=g.|
-000002f0 28 b8 8c 6d 66 7e ab 82 c9 f6 d0 49 62 96 2c af |(..mf~.....Ib.,.|
-00000300 4f 0a d1 21 54 b8 3e ae 09 fd d8 85 10 cb da c4 |O..!T.>.........|
-00000310 6f 42 16 cd 70 cd 33 b0 a5 e5 a1 c7 9a 35 41 3f |oB..p.3......5A?|
-00000320 59 db a1 b3 f4 ae f6 72 9c a8 db f5 86 99 43 b3 |Y......r......C.|
-00000330 8f bc 0f d9 0a 50 49 58 3b 17 fa 51 27 11 e9 95 |.....PIX;..Q'...|
-00000340 8c bb 1a 31 11 bc a2 fa 2c 6b c2 6a 40 16 03 01 |...1....,k.j@...|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 00 80 bb 96 fe |......_X.;t.....|
+000002d0 bf a0 81 24 bc 40 b4 e2 37 b1 c9 66 2d c3 c1 bb |...$.@..7..f-...|
+000002e0 89 fb 28 23 60 76 b1 e6 2c c1 e9 06 d0 95 c5 10 |..(#`v..,.......|
+000002f0 17 ce 79 36 c2 14 e0 1d 1d 0d 0e 49 3e b9 7f 00 |..y6.......I>...|
+00000300 ad e3 1d 37 ab ce 2c 37 dc eb be aa 6c 28 33 05 |...7..,7....l(3.|
+00000310 53 fd 06 17 b4 85 b9 b8 35 1c a7 3c bb 07 3f 4b |S.......5..<..?K|
+00000320 53 98 00 4d 8e 49 bd 35 55 64 92 d0 a0 db 05 80 |S..M.I.5Ud......|
+00000330 57 24 78 cd 10 ed ae f0 6a 83 bc b4 4d 77 79 ba |W$x.....j...Mwy.|
+00000340 6e e7 2e 8f ac 9e 98 34 36 9d a9 27 f0 16 03 01 |n......46..'....|
00000350 00 04 0e 00 00 00 |......|
>>> Flow 3 (client to server)
-00000000 16 03 01 00 25 10 00 00 21 20 bf 0c 33 f5 6a 06 |....%...! ..3.j.|
-00000010 18 0a 74 ad 8b bd ef 9c 00 a3 c0 03 20 5b ea 69 |..t......... [.i|
-00000020 09 18 b8 4a 30 13 c7 10 30 3a 14 03 01 00 01 01 |...J0...0:......|
-00000030 16 03 01 00 30 04 6d f7 66 e9 7f 72 80 32 24 93 |....0.m.f..r.2$.|
-00000040 2f 74 5e 34 c5 fb 19 a0 64 31 1e cb 63 03 fb 51 |/t^4....d1..c..Q|
-00000050 5c d9 17 a8 b0 8a b6 74 e8 84 86 a5 33 d2 75 4a |\......t....3.uJ|
-00000060 c0 bb 6a bb f3 |..j..|
+00000000 16 03 01 00 25 10 00 00 21 20 00 ad c5 2b 21 7f |....%...! ...+!.|
+00000010 8e 44 f2 f5 32 22 c8 c2 c6 de 2c 0b 7a a9 24 b6 |.D..2"....,.z.$.|
+00000020 03 20 c0 cc 79 2e 11 2f d3 43 14 03 01 00 01 01 |. ..y../.C......|
+00000030 16 03 01 00 30 78 5c 32 72 a1 c8 3b 9c 7b 77 0b |....0x\2r..;.{w.|
+00000040 a0 28 52 55 17 16 d5 39 89 d0 43 bf 67 29 85 6f |.(RU...9..C.g).o|
+00000050 b5 1e 83 fa 22 96 78 e3 5c 45 5a 3d fe 2b d5 b7 |....".x.\EZ=.+..|
+00000060 3d 64 44 8c a8 |=dD..|
>>> Flow 4 (server to client)
-00000000 16 03 01 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 01 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6d ec a4 83 61 28 8e b8 1b 0e dd 7d 71 4a 36 c3 |m...a(.....}qJ6.|
-00000040 6d cb c7 88 ed 19 c5 08 72 b9 25 fb 6c 29 b8 b2 |m.......r.%.l)..|
-00000050 72 f8 27 c0 1e f2 86 16 54 0f 72 a9 6e 15 69 9e |r.'.....T.r.n.i.|
-00000060 66 fe d1 05 20 33 94 32 40 82 bb e3 61 47 3a 8e |f... 3.2@...aG:.|
-00000070 b7 45 92 8a 5c 84 64 eb 6c 1a 3c bb 2f be ce b2 |.E..\.d.l.<./...|
-00000080 5f cb c9 be c4 ff d6 14 03 01 00 01 01 16 03 01 |_...............|
-00000090 00 30 5e ff 91 82 d5 30 a4 fb cd 20 90 c1 2d 08 |.0^....0... ..-.|
-000000a0 aa 19 d6 72 fa 74 07 95 df 14 eb 59 bb 0c 81 3f |...r.t.....Y...?|
-000000b0 75 77 45 96 d8 3e 45 a7 42 1c f1 82 c0 04 4d 2e |uwE..>E.B.....M.|
-000000c0 3f 07 17 03 01 00 20 54 90 60 76 16 5f 6b d0 3e |?..... T.`v._k.>|
-000000d0 f6 bf f3 0a 5c b9 3b 19 cb df a6 94 28 04 24 ea |....\.;.....(.$.|
-000000e0 73 1f 49 5e 23 f6 91 17 03 01 00 30 b5 97 eb 85 |s.I^#......0....|
-000000f0 cc 17 86 b0 0d 24 bf 64 6d 4f 16 55 b0 f3 64 7c |.....$.dmO.U..d||
-00000100 75 3f e4 16 94 41 56 64 12 50 0e 7c 0c 1c e7 58 |u?...AVd.P.|...X|
-00000110 4d 9c 82 d8 f5 5a 61 a3 d8 3c f5 04 15 03 01 00 |M....Za..<......|
-00000120 20 59 6c e6 9e 4e 14 94 5d 61 94 b2 ba 0f eb 18 | Yl..N..]a......|
-00000130 cf 10 5b f6 90 27 58 8e 10 54 36 d4 c7 52 37 2e |..[..'X..T6..R7.|
-00000140 a0 |.|
+00000030 6d ec a4 83 51 ed 14 ef 68 ca 42 c5 4c 5f bb 3b |m...Q...h.B.L_.;|
+00000040 9c c8 3c 7e 1c cf dc da e4 35 83 03 13 95 82 5f |..<~.....5....._|
+00000050 32 77 8a cf dc e9 10 65 9b 97 d4 5d ff 43 57 14 |2w.....e...].CW.|
+00000060 a3 25 e0 fa c8 26 0c ff 71 67 9b 32 2f 49 38 16 |.%...&..qg.2/I8.|
+00000070 aa ea b9 fa 99 86 4c b9 db 7a ef bc 87 43 e8 db |......L..z...C..|
+00000080 26 27 73 76 80 77 59 c4 fb 7d 56 e9 7e 23 03 75 |&'sv.wY..}V.~#.u|
+00000090 14 03 01 00 01 01 16 03 01 00 30 80 8f 8e 11 b5 |..........0.....|
+000000a0 f4 a0 8c 4a ae 3f 25 17 66 93 1c c5 a5 10 57 e3 |...J.?%.f.....W.|
+000000b0 24 7a c1 a9 72 74 4f fd 20 5e 5b 58 4d bd 5d f0 |$z..rtO. ^[XM.].|
+000000c0 05 8e 06 61 0a 98 19 a0 a8 73 02 17 03 01 00 20 |...a.....s..... |
+000000d0 d9 dd 86 e6 55 55 df 2c 0d 1e 5f 0e 9e 1e 76 51 |....UU.,.._...vQ|
+000000e0 98 e0 2b 09 f9 44 4d 4d 22 97 0d 1e 95 7b b9 41 |..+..DMM"....{.A|
+000000f0 17 03 01 00 30 74 82 1c 35 9b 87 cd 5e 29 95 e1 |....0t..5...^)..|
+00000100 18 e3 76 32 94 b5 1b d0 06 d2 ec 49 40 24 73 d3 |..v2.......I@$s.|
+00000110 fc 5d 1a 26 59 5b 33 d8 5a 30 d5 92 30 bc 80 e0 |.].&Y[3.Z0..0...|
+00000120 ed 85 e8 14 01 15 03 01 00 20 ec 69 2f 9d 29 4f |......... .i/.)O|
+00000130 1f 8e e6 34 f0 87 66 40 e8 13 14 02 74 c4 1d aa |...4..f@....t...|
+00000140 65 72 43 50 6e 71 9c 2e b6 3a |erCPnq...:|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
index f6ddb972f6..d9e7e83766 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -1,19 +1,18 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 e3 01 00 00 df 03 03 e7 33 0d 6a 2d |............3.j-|
-00000010 87 bc b4 a1 11 ee 1a 4e 91 f5 fb ad 29 70 d4 6d |.......N....)p.m|
-00000020 05 be ec f3 e2 b1 0d 4e da a4 b5 00 00 38 c0 2c |.......N.....8.,|
+00000000 16 03 01 00 d1 01 00 00 cd 03 03 50 99 a9 e9 80 |...........P....|
+00000010 87 f1 0a 5a bc 9d a6 53 6d 08 36 4a 79 f8 48 c3 |...Z...Sm.6Jy.H.|
+00000020 fe c1 b4 02 d9 66 b2 cc f9 8d d4 00 00 38 c0 2c |.....f.......8.,|
00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
-00000060 00 35 00 2f 00 ff 01 00 00 7e 00 00 00 0e 00 0c |.5./.....~......|
-00000070 00 00 09 31 32 37 2e 30 2e 30 2e 31 00 0b 00 04 |...127.0.0.1....|
-00000080 03 00 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e |................|
-00000090 00 19 00 18 00 23 00 00 00 10 00 10 00 0e 06 70 |.....#.........p|
-000000a0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
-000000b0 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 |.......0........|
-000000c0 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 |................|
-000000d0 04 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 |................|
-000000e0 02 02 04 02 05 02 06 02 |........|
+00000060 00 35 00 2f 00 ff 01 00 00 6c 00 0b 00 04 03 00 |.5./.....l......|
+00000070 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000080 00 18 00 23 00 00 00 10 00 10 00 0e 06 70 72 6f |...#.........pro|
+00000090 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 00 17 |to2.proto1......|
+000000a0 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+000000b0 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+000000c0 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+000000d0 04 02 05 02 06 02 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 48 02 00 00 44 03 03 00 00 00 00 00 |....H...D.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -60,38 +59,38 @@
000002a0 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac |=.`.\!.;........|
000002b0 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 |....... /.}.G.bC|
000002c0 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 |.(.._.).0.......|
-000002d0 ed 90 99 5f 58 cb 3b 74 08 04 00 80 b6 a2 61 f9 |..._X.;t......a.|
-000002e0 30 40 0b 5c 2c 92 b4 7b e3 42 79 00 11 4d 6b 85 |0@.\,..{.By..Mk.|
-000002f0 df 2e 19 c2 fc a8 bc 16 0b c0 8d 02 55 99 a7 06 |............U...|
-00000300 fa 4c 4d 4c 27 de 6d 3d 1e 7a 6f 2c fc eb 9e 15 |.LML'.m=.zo,....|
-00000310 40 6f 0c 81 b3 e1 4d 78 b7 38 c6 50 8f 5b 63 ac |@o....Mx.8.P.[c.|
-00000320 20 4f a6 06 aa 00 84 f5 01 f4 68 7a 5a 16 c5 da | O........hzZ...|
-00000330 71 b2 4f 04 6e 59 88 14 8c 81 01 91 a8 e8 c1 18 |q.O.nY..........|
-00000340 a8 07 e8 7a f4 dc b9 e7 7f c5 ce 2c 32 8d fe d6 |...z.......,2...|
-00000350 1f 0e a5 f0 f4 c7 dd 39 13 a1 ca 6d 16 03 03 00 |.......9...m....|
+000002d0 ed 90 99 5f 58 cb 3b 74 08 04 00 80 cb 03 45 70 |..._X.;t......Ep|
+000002e0 f5 51 af d7 cf db 26 79 d1 57 c2 06 4c 49 e6 ea |.Q....&y.W..LI..|
+000002f0 e7 f4 b8 2c 23 52 8a 1f bd 8e a3 9e 79 d4 8e 66 |...,#R......y..f|
+00000300 ee 92 39 97 cc ec 46 03 76 f9 59 b7 2e 6f e4 88 |..9...F.v.Y..o..|
+00000310 fd 39 65 59 88 c2 7e 7a bc de 86 49 98 45 a6 44 |.9eY..~z...I.E.D|
+00000320 82 41 19 94 53 3d 34 4b 73 52 5a af b2 3d 92 5e |.A..S=4KsRZ..=.^|
+00000330 f3 5b e8 fa 23 a7 71 5c 64 1b 43 bb bd 8e 01 2a |.[..#.q\d.C....*|
+00000340 59 2d 3b 73 0f b9 3d 02 9a 09 4a fc 0e 4b 65 07 |Y-;s..=...J..Ke.|
+00000350 82 f9 e1 ad ec 64 27 a4 07 60 c7 32 16 03 03 00 |.....d'..`.2....|
00000360 04 0e 00 00 00 |.....|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 25 10 00 00 21 20 d7 fa 22 66 b4 c8 |....%...! .."f..|
-00000010 67 2c 45 93 bf 38 3a 13 21 45 d5 29 95 5b 0d 5c |g,E..8:.!E.).[.\|
-00000020 79 d2 d6 9b ef bd 7d eb a9 21 14 03 03 00 01 01 |y.....}..!......|
-00000030 16 03 03 00 28 a2 81 84 32 29 01 69 28 f9 56 cc |....(...2).i(.V.|
-00000040 c9 72 51 5c 22 38 51 12 e1 55 a1 d6 8c cf 66 75 |.rQ\"8Q..U....fu|
-00000050 b4 bd 49 60 d0 e4 7e 9e fe 56 d1 62 36 |..I`..~..V.b6|
+00000000 16 03 03 00 25 10 00 00 21 20 f6 5d 24 8e fc 1c |....%...! .]$...|
+00000010 39 bb 01 fc 23 ef f4 86 8b aa 2c 39 2a a1 4d e6 |9...#.....,9*.M.|
+00000020 7c 21 74 cc ed 2c 9b 4b f2 01 14 03 03 00 01 01 ||!t..,.K........|
+00000030 16 03 03 00 28 96 9c a6 78 4b 94 24 e2 31 5a 25 |....(...xK.$.1Z%|
+00000040 68 5e 6a 51 03 5d 9d cf 45 b1 78 17 0b bf ff c6 |h^jQ.]..E.x.....|
+00000050 72 5b e9 f0 a1 b1 46 ab a5 e1 3f 4d 67 |r[....F...?Mg|
>>> Flow 4 (server to client)
-00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 cf 87 48 45 0d 9d a5 bf 38 b4 9f |o...a..HE....8..|
-00000040 19 a9 cd ca 63 79 2d c3 ae 70 74 56 44 99 fb cc |....cy-..ptVD...|
-00000050 7d 31 c2 67 75 fe 57 1b fd 6b 2f cd df ec fa 5b |}1.gu.W..k/....[|
-00000060 23 47 19 7e 84 33 94 d7 de e2 b9 ff 75 7d dc 80 |#G.~.3......u}..|
-00000070 9e 55 94 8e 15 94 70 8f b5 21 0e 4e f7 4c e6 44 |.U....p..!.N.L.D|
-00000080 01 a3 9d 67 5f 05 73 14 03 03 00 01 01 16 03 03 |...g_.s.........|
-00000090 00 28 00 00 00 00 00 00 00 00 3a 49 dc e2 aa ce |.(........:I....|
-000000a0 a8 43 27 08 a8 6b 7c ae 3f 07 18 e1 04 a9 e6 24 |.C'..k|.?......$|
-000000b0 0e 9e 0a 0f af a4 c3 6e 90 2d 17 03 03 00 25 00 |.......n.-....%.|
-000000c0 00 00 00 00 00 00 01 41 e1 9b 4c 8a 1a e8 10 bf |.......A..L.....|
-000000d0 9f fd 76 e4 43 c2 cf 04 ee 68 6a 02 3c 97 fc ec |..v.C....hj.<...|
-000000e0 c4 0a 74 1d 15 03 03 00 1a 00 00 00 00 00 00 00 |..t.............|
-000000f0 02 1c 9b b1 b6 07 fa 33 a8 70 03 d9 27 29 ea 61 |.......3.p..').a|
-00000100 96 c2 48 |..H|
+00000030 6f ec 80 83 51 ed 14 ef 68 ca 42 c5 4c 4a f5 b1 |o...Q...h.B.LJ..|
+00000040 56 86 3e f2 10 79 9e f3 a0 ed 07 6d 09 fc 77 63 |V.>..y.....m..wc|
+00000050 86 68 42 99 7b 13 c3 35 cf 5b a6 3a fa aa c2 ec |.hB.{..5.[.:....|
+00000060 80 a2 27 e4 97 24 07 48 2c 70 30 fc d6 49 38 16 |..'..$.H,p0..I8.|
+00000070 60 d5 b0 4c ec 4b 74 48 03 2a 5e fb 14 43 6c 5f |`..L.KtH.*^..Cl_|
+00000080 35 9c 1b a8 7d 62 f8 42 68 27 cb 6d 15 38 e7 8e |5...}b.Bh'.m.8..|
+00000090 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+000000a0 00 00 00 8d 7a 5a 66 3b c9 fe 51 c2 71 ef a5 8b |....zZf;..Q.q...|
+000000b0 42 7d 79 33 4e 6d 66 12 cc e7 46 4f c3 30 12 8f |B}y3Nmf...FO.0..|
+000000c0 0c 57 60 17 03 03 00 25 00 00 00 00 00 00 00 01 |.W`....%........|
+000000d0 83 aa 62 fe a3 73 ed 67 87 c0 19 1c fa f0 2c 26 |..b..s.g......,&|
+000000e0 4b 16 44 9c a7 f8 c3 e1 ba 6a 85 8f 84 15 03 03 |K.D......j......|
+000000f0 00 1a 00 00 00 00 00 00 00 02 a8 b3 b2 dd 4b a6 |..............K.|
+00000100 ba 05 dc 8f ac 98 ae 01 10 60 9a 62 |.........`.b|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
index f8b88a63d7..589189ca84 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -1,19 +1,18 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 e3 01 00 00 df 03 03 ed dd 7f 68 1d |..............h.|
-00000010 9e 83 bc 08 01 39 8e 97 76 91 cb cb 24 73 15 f5 |.....9..v...$s..|
-00000020 17 17 db 78 69 ca e1 ed 0f fc bc 00 00 38 c0 2c |...xi........8.,|
+00000000 16 03 01 00 d1 01 00 00 cd 03 03 44 a5 b9 48 dd |...........D..H.|
+00000010 ca 91 9a c6 72 06 b3 dd a7 95 18 c6 95 0b f2 32 |....r..........2|
+00000020 84 37 78 12 0f 66 c7 6e e6 61 81 00 00 38 c0 2c |.7x..f.n.a...8.,|
00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
-00000060 00 35 00 2f 00 ff 01 00 00 7e 00 00 00 0e 00 0c |.5./.....~......|
-00000070 00 00 09 31 32 37 2e 30 2e 30 2e 31 00 0b 00 04 |...127.0.0.1....|
-00000080 03 00 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e |................|
-00000090 00 19 00 18 00 23 00 00 00 10 00 10 00 0e 06 70 |.....#.........p|
-000000a0 72 6f 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 |roto2.proto1....|
-000000b0 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 |.......0........|
-000000c0 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 |................|
-000000d0 04 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 |................|
-000000e0 02 02 04 02 05 02 06 02 |........|
+00000060 00 35 00 2f 00 ff 01 00 00 6c 00 0b 00 04 03 00 |.5./.....l......|
+00000070 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000080 00 18 00 23 00 00 00 10 00 10 00 0e 06 70 72 6f |...#.........pro|
+00000090 74 6f 32 06 70 72 6f 74 6f 31 00 16 00 00 00 17 |to2.proto1......|
+000000a0 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+000000b0 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+000000c0 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+000000d0 04 02 05 02 06 02 |......|
>>> Flow 2 (server to client)
00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -59,38 +58,38 @@
00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
-000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 59 |......_X.;t....Y|
-000002d0 85 20 dc b1 4c d2 17 4d 20 73 1a a7 f7 ab 40 52 |. ..L..M s....@R|
-000002e0 73 e7 02 21 eb 55 e2 c9 73 c0 c2 8a ed a3 fd 07 |s..!.U..s.......|
-000002f0 0b 5b 30 c2 1e 63 a1 c2 27 41 6c 5a ca 6e 12 d3 |.[0..c..'AlZ.n..|
-00000300 4a 87 15 29 7f 44 06 3d 14 76 98 45 e5 27 84 09 |J..).D.=.v.E.'..|
-00000310 44 be f3 c4 ce 79 31 e9 92 06 b6 d2 d9 19 d1 24 |D....y1........$|
-00000320 7d 44 6a 57 ea 9d 12 e3 e7 a1 16 86 10 fc 7a 66 |}DjW..........zf|
-00000330 00 3a f0 f0 ed e7 7c 20 82 0a 26 5d 92 79 8a 5b |.:....| ..&].y.[|
-00000340 55 98 fc 1a c1 2f c0 07 ce b8 03 3a 01 da 62 16 |U..../.....:..b.|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 1d |......_X.;t.....|
+000002d0 ae 16 b9 7e 58 bb d5 1b 9e 51 09 a2 d1 a8 3f 1d |...~X....Q....?.|
+000002e0 f4 09 72 a5 c6 cc 9a 53 46 1c 9f 58 36 cd 91 39 |..r....SF..X6..9|
+000002f0 44 ca 56 da 50 77 d5 56 10 14 45 ad 98 b8 2f 44 |D.V.Pw.V..E.../D|
+00000300 33 ae a9 b1 b6 a6 2a ab 0a 0a 39 75 2c 4d 4c 51 |3.....*...9u,MLQ|
+00000310 71 07 83 bf ad 8b 37 c5 59 dd 8f d7 b8 85 2e 04 |q.....7.Y.......|
+00000320 9e 39 e6 e5 a5 48 9a 24 63 b3 a7 46 73 b2 5c 10 |.9...H.$c..Fs.\.|
+00000330 cc 4c e5 55 dd 97 b0 42 4e 8b fb 0d cd 47 e9 09 |.L.U...BN....G..|
+00000340 20 88 96 5e 76 0d 9b b1 91 3f 27 a1 f3 0d 77 16 | ..^v....?'...w.|
00000350 03 03 00 04 0e 00 00 00 |........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 25 10 00 00 21 20 d9 f2 e4 c5 cf 38 |....%...! .....8|
-00000010 23 30 2e b6 d9 0f 3b a2 d7 2f eb d5 74 a8 29 12 |#0....;../..t.).|
-00000020 5f 27 bc 81 96 6b 12 5a bb 2f 14 03 03 00 01 01 |_'...k.Z./......|
-00000030 16 03 03 00 28 4b a1 12 ce 11 2a 0f 79 7c 56 eb |....(K....*.y|V.|
-00000040 bb 9f 7d 91 c7 53 25 d6 ae 0b 98 f1 b5 ea ef 51 |..}..S%........Q|
-00000050 8b 3a fb d1 6c ae 3d bb b7 67 d9 ba 36 |.:..l.=..g..6|
+00000000 16 03 03 00 25 10 00 00 21 20 89 8e 03 11 92 ab |....%...! ......|
+00000010 51 f5 d7 dc 27 87 fd 38 eb 45 3d cc 75 1a 1e 07 |Q...'..8.E=.u...|
+00000020 d6 0f 2b 92 df 5a 7c 24 30 56 14 03 03 00 01 01 |..+..Z|$0V......|
+00000030 16 03 03 00 28 fa 24 69 6d 65 2f 34 35 47 9b 83 |....(.$ime/45G..|
+00000040 65 0f fd c1 33 61 1d 47 cf ec 87 6f 48 71 63 7d |e...3a.G...oHqc}|
+00000050 e8 aa bc 2e cd 7d 2e 4b d5 0f 4f 66 14 |.....}.K..Of.|
>>> Flow 4 (server to client)
-00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 40 f9 2b 9e a7 30 60 fb 46 36 c4 |o...a@.+..0`.F6.|
-00000040 0e b3 2a c4 73 64 2e 12 6c 0d f5 b9 6f 05 ae 27 |..*.sd..l...o..'|
-00000050 d7 a3 47 c5 67 31 3e 95 84 bf 42 e1 b9 0d 90 40 |..G.g1>...B....@|
-00000060 01 50 0d 32 4b 33 94 5c a3 1d b9 db e5 c5 24 02 |.P.2K3.\......$.|
-00000070 48 31 ad 70 8e c7 e9 60 a5 7e ea 91 7b 01 79 06 |H1.p...`.~..{.y.|
-00000080 66 f9 c4 9d bd 65 a5 14 03 03 00 01 01 16 03 03 |f....e..........|
-00000090 00 28 00 00 00 00 00 00 00 00 32 be b5 c5 4d 83 |.(........2...M.|
-000000a0 41 97 f6 26 0f aa 06 35 d5 9e f8 12 1c 04 f7 b6 |A..&...5........|
-000000b0 16 9f f9 a4 43 b8 56 ea 4a 82 17 03 03 00 25 00 |....C.V.J.....%.|
-000000c0 00 00 00 00 00 00 01 1a 8e 6b 4a 69 02 56 46 eb |.........kJi.VF.|
-000000d0 26 12 47 a3 9d 9a 8a 09 20 4a 6c b2 d0 6a 14 48 |&.G..... Jl..j.H|
-000000e0 be d5 f0 48 15 03 03 00 1a 00 00 00 00 00 00 00 |...H............|
-000000f0 02 0e 01 9d 60 90 01 60 99 a0 f5 df 6d 38 e5 76 |....`..`....m8.v|
-00000100 4d d7 d7 |M..|
+00000030 6f ec 80 83 51 ed 14 ef 68 ca 42 c5 4c 60 05 16 |o...Q...h.B.L`..|
+00000040 33 5b f7 bd 83 9c 69 80 c2 fe 5c 73 32 05 67 97 |3[....i...\s2.g.|
+00000050 fd 6b 3a d3 b4 6d a5 5e 18 c0 1e ba d5 2c 44 ad |.k:..m.^.....,D.|
+00000060 54 24 65 be 14 90 ab 6d a1 de d1 98 1e 49 38 16 |T$e....m.....I8.|
+00000070 f0 fe 8d 49 6d e1 5a 6d 10 30 26 64 5f 10 ad ab |...Im.Zm.0&d_...|
+00000080 d7 c9 3a bc 6a 3f 32 78 4b fe f1 38 08 2c 15 e7 |..:.j?2xK..8.,..|
+00000090 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+000000a0 00 00 00 e9 3d 4c 8b 59 78 8c 49 77 08 3b c1 de |....=L.Yx.Iw.;..|
+000000b0 4c 78 9a d7 c6 1a 66 fb 43 de bd cb 8b ca a2 32 |Lx....f.C......2|
+000000c0 a2 26 1e 17 03 03 00 25 00 00 00 00 00 00 00 01 |.&.....%........|
+000000d0 47 c9 3a 0d 8d 8b d1 b7 66 17 8e 83 31 02 ed 51 |G.:.....f...1..Q|
+000000e0 e8 cb 1d 4a 42 d6 f9 ee b8 6d fd d0 4b 15 03 03 |...JB....m..K...|
+000000f0 00 1a 00 00 00 00 00 00 00 02 f3 00 56 6d fc 23 |............Vm.#|
+00000100 49 bb 65 00 b0 ae cd c7 62 ac 47 1f |I.e.....b.G.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
index ecf765be7d..c9f0c5c0fc 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
+++ b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
@@ -1,18 +1,17 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 cf 01 00 00 cb 03 03 62 4c 73 03 fd |...........bLs..|
-00000010 24 98 d0 f6 41 49 83 94 04 c8 17 51 3e 18 5d 6d |$...AI.....Q>.]m|
-00000020 8a b8 52 c0 cf 0b 60 1e 02 53 d2 00 00 38 c0 2c |..R...`..S...8.,|
+00000000 16 03 01 00 bd 01 00 00 b9 03 03 7e 75 ea 1f ec |...........~u...|
+00000010 47 ee de 51 9d 11 00 77 5b 1b fb 7e 05 22 0a 7a |G..Q...w[..~.".z|
+00000020 74 bc 6a d1 8a 67 03 a1 ae c9 23 00 00 38 c0 2c |t.j..g....#..8.,|
00000030 c0 30 00 9f cc a9 cc a8 cc aa c0 2b c0 2f 00 9e |.0.........+./..|
00000040 c0 24 c0 28 00 6b c0 23 c0 27 00 67 c0 0a c0 14 |.$.(.k.#.'.g....|
00000050 00 39 c0 09 c0 13 00 33 00 9d 00 9c 00 3d 00 3c |.9.....3.....=.<|
-00000060 00 35 00 2f 00 ff 01 00 00 6a 00 00 00 0e 00 0c |.5./.....j......|
-00000070 00 00 09 31 32 37 2e 30 2e 30 2e 31 00 0b 00 04 |...127.0.0.1....|
-00000080 03 00 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e |................|
-00000090 00 19 00 18 00 23 00 00 00 16 00 00 00 17 00 00 |.....#..........|
-000000a0 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 |...0............|
-000000b0 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 |................|
-000000c0 06 01 03 03 02 03 03 01 02 01 03 02 02 02 04 02 |................|
-000000d0 05 02 06 02 |....|
+00000060 00 35 00 2f 00 ff 01 00 00 58 00 0b 00 04 03 00 |.5./.....X......|
+00000070 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000080 00 18 00 23 00 00 00 16 00 00 00 17 00 00 00 0d |...#............|
+00000090 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+000000a0 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+000000b0 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+000000c0 06 02 |..|
>>> Flow 2 (server to client)
00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
@@ -58,38 +57,38 @@
00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
-000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 2d |......_X.;t....-|
-000002d0 54 87 fa c9 e5 97 ad a0 6d 54 89 b1 37 24 af df |T.......mT..7$..|
-000002e0 0f 3e ef 34 f7 6a 5f 1b 06 a5 b9 b4 6d 46 7f b1 |.>.4.j_.....mF..|
-000002f0 ab e4 5c dd c1 3f 98 93 61 e5 81 8a 6c 3d 2f b3 |..\..?..a...l=/.|
-00000300 3c 59 b9 78 45 ba bd 02 b1 a0 72 cb c3 59 b1 55 |<Y.xE.....r..Y.U|
-00000310 da a3 a8 ea ac b2 8a c0 23 e7 e7 ca c9 9f 5d 1b |........#.....].|
-00000320 a8 b4 7c c3 9f cf c5 3c 5f 07 d8 49 8c 95 f1 ce |..|....<_..I....|
-00000330 27 d0 d1 3f 74 44 df e4 12 ea e2 0e 43 6e d2 53 |'..?tD......Cn.S|
-00000340 7e 39 41 d7 71 c1 3c 2c a6 0b 4e e3 4d 9a 02 16 |~9A.q.<,..N.M...|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 d9 |......_X.;t.....|
+000002d0 5f d9 85 1f 13 34 60 85 c8 eb 27 79 14 ed 84 77 |_....4`...'y...w|
+000002e0 98 60 72 ce ee b9 92 87 50 4b 4a f8 25 7f 8d 92 |.`r.....PKJ.%...|
+000002f0 16 2a 19 65 96 b4 30 af fd 1b fe 1c 02 1f f4 77 |.*.e..0........w|
+00000300 6f 63 53 7c 54 a0 89 5d e9 32 b3 a9 5f e6 4b 60 |ocS|T..].2.._.K`|
+00000310 8b b1 c8 d2 61 8b 19 59 f3 5a b4 e2 71 16 b8 32 |....a..Y.Z..q..2|
+00000320 1f 8c 74 e2 4e 17 56 7e 69 01 39 8c c1 cf c7 0b |..t.N.V~i.9.....|
+00000330 56 c6 f6 c0 37 7b 3d 65 48 40 6b a0 67 e6 cd 70 |V...7{=eH@k.g..p|
+00000340 ce 8c 73 d4 e9 ba c0 04 18 b3 37 06 71 66 72 16 |..s.......7.qfr.|
00000350 03 03 00 04 0e 00 00 00 |........|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 25 10 00 00 21 20 37 47 1b 8d ef 6c |....%...! 7G...l|
-00000010 dc 59 b2 a5 a2 f6 8e 1b f6 1b ab da ec 9c a7 ff |.Y..............|
-00000020 4a f9 0e 9b 02 b0 8f bc a1 55 14 03 03 00 01 01 |J........U......|
-00000030 16 03 03 00 28 a2 53 52 8b df 86 63 d9 f8 a8 7e |....(.SR...c...~|
-00000040 f5 b4 19 1a 5d 02 9a 48 94 68 6d a2 90 13 93 42 |....]..H.hm....B|
-00000050 87 52 92 50 7c 45 91 b9 91 49 83 66 a6 |.R.P|E...I.f.|
+00000000 16 03 03 00 25 10 00 00 21 20 d5 13 c6 90 e0 4a |....%...! .....J|
+00000010 25 2f 5d cd 02 d8 fd 14 61 78 dd fc 42 57 ce bd |%/].....ax..BW..|
+00000020 e0 47 b8 cf 42 59 1c 7f 1f 1e 14 03 03 00 01 01 |.G..BY..........|
+00000030 16 03 03 00 28 96 2c 78 25 ee 20 88 53 69 57 96 |....(.,x%. .SiW.|
+00000040 d9 d2 53 6c 5b 5b e9 db 7d 0a 7c f9 16 27 43 df |..Sl[[..}.|..'C.|
+00000050 a9 e2 a6 e5 be c5 e9 d5 ff df 66 6b 81 |..........fk.|
>>> Flow 4 (server to client)
-00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f ec 80 83 61 a2 90 f4 4c 03 c8 09 b9 a6 c6 6f |o...a...L......o|
-00000040 c7 52 57 3f 3f 92 71 f3 f8 02 43 69 19 f0 bf 78 |.RW??.q...Ci...x|
-00000050 6a 00 cc 0a 96 6f 80 5d 62 42 9b 6b 7c 00 e0 26 |j....o.]bB.k|..&|
-00000060 90 ef d9 26 f1 33 94 6e 13 9a ec be 91 00 1e 64 |...&.3.n.......d|
-00000070 eb 12 ae b9 74 f9 85 d1 b7 91 bd e1 e2 da ac b0 |....t...........|
-00000080 71 ca 1b 65 1a e7 83 14 03 03 00 01 01 16 03 03 |q..e............|
-00000090 00 28 00 00 00 00 00 00 00 00 fa e4 1b 3b 28 9b |.(...........;(.|
-000000a0 f8 28 d7 26 d7 6a 67 33 1f 4a 39 d9 ac 59 6f fc |.(.&.jg3.J9..Yo.|
-000000b0 2b 84 6c b9 73 70 9b 30 8c d0 17 03 03 00 25 00 |+.l.sp.0......%.|
-000000c0 00 00 00 00 00 00 01 0c 6e 13 cf 3d 10 65 2f e5 |........n..=.e/.|
-000000d0 4f fd f9 b6 34 11 c2 05 60 d5 16 66 68 65 29 fa |O...4...`..fhe).|
-000000e0 e6 97 e4 dc 15 03 03 00 1a 00 00 00 00 00 00 00 |................|
-000000f0 02 58 9a 0d 41 6f 0f 72 c7 43 16 46 83 dd 26 5f |.X..Ao.r.C.F..&_|
-00000100 3a ee 1a |:..|
+00000030 6f ec 80 83 51 ed 14 ef 68 ca 42 c5 4c c7 ea d3 |o...Q...h.B.L...|
+00000040 9f e6 77 db 30 96 5c e3 bc f8 b7 c7 74 9d 0e 97 |..w.0.\.....t...|
+00000050 cf 3c ec 76 c8 9e ad 0c 49 86 9e 4f 4d 56 ce 95 |.<.v....I..OMV..|
+00000060 7f 75 79 aa dd 8e 66 8f 1f d8 01 2d c1 49 38 16 |.uy...f....-.I8.|
+00000070 b3 7a 6b 8d 3d ba 2b 81 4c 1c 75 c3 06 bb 8c 1e |.zk.=.+.L.u.....|
+00000080 df 59 35 29 5b d1 54 cc 5c 6b 37 74 29 19 0f 8b |.Y5)[.T.\k7t)...|
+00000090 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+000000a0 00 00 00 c7 19 9a c9 cc 16 3b 8f b7 52 de 4c ab |.........;..R.L.|
+000000b0 90 83 b1 b5 60 0d c0 49 c4 28 f7 1d 1f e9 e0 b1 |....`..I.(......|
+000000c0 21 a1 49 17 03 03 00 25 00 00 00 00 00 00 00 01 |!.I....%........|
+000000d0 46 fe 03 14 ad 32 d5 ff 89 1f 08 15 6b 44 4f 2d |F....2......kDO-|
+000000e0 5e d6 f1 35 d9 c4 c4 cc bf 5a 26 df a6 15 03 03 |^..5.....Z&.....|
+000000f0 00 1a 00 00 00 00 00 00 00 02 4f 7b 8e 22 3c 85 |..........O{."<.|
+00000100 5c 41 f5 17 0d dd c8 41 b5 ef 5a 4c |\A.....A..ZL|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
index 42cbc3420d..73d01585eb 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -1,92 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 9b 01 00 00 97 03 03 22 89 61 60 36 |...........".a`6|
-00000010 06 c6 00 3f af 09 28 13 d8 7e ae 18 55 40 4a 4e |...?..(..~..U@JN|
-00000020 40 13 e2 f8 43 5f be e5 f6 51 04 00 00 04 00 2f |@...C_...Q...../|
-00000030 00 ff 01 00 00 6a 00 00 00 0e 00 0c 00 00 09 31 |.....j.........1|
-00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
-00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
-00000060 00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 30 |.#.............0|
-00000070 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 08 0a |................|
-00000080 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 03 03 |................|
-00000090 02 03 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |................|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 60 fd 9b 74 aa |....q...m..`..t.|
+00000010 16 9f 07 32 7e 57 d0 91 86 ea 59 b7 f3 38 bb 4f |...2~W....Y..8.O|
+00000020 7f 2c 36 eb 67 21 57 f2 12 2b 38 00 00 04 00 2f |.,6.g!W..+8..../|
+00000030 00 ff 01 00 00 40 00 23 00 00 00 16 00 00 00 17 |.....@.#........|
+00000040 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+00000050 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+00000060 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+00000070 04 02 05 02 06 02 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
-00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
-00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
-00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
-00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
-00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
-00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
-00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
-000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
-000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
-000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
-000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
-000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
-000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
-00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
-00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
-00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
-00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
-00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
-00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
-00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
-00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
-00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
-00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
-000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
-000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
-000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
-000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
-000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
-000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
-00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
-00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
-00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
-00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
-00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
-00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
-00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
-00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
-00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
-00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
-000002a0 03 00 04 0e 00 00 00 |.......|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 d0 71 60 6a 92 |............q`j.|
-00000010 9b 01 87 1b d3 7d 28 a8 50 aa b9 c3 0e a3 b0 2d |.....}(.P......-|
-00000020 2f 29 1d f1 42 39 6f 65 bb 1a 0e bc 82 43 e9 c6 |/)..B9oe.....C..|
-00000030 c6 cc df 4e c6 f2 2b 85 26 cb 63 12 f7 a1 84 a1 |...N..+.&.c.....|
-00000040 25 8b 8f 02 f2 c1 fe 09 79 89 ba da b7 b1 32 4c |%.......y.....2L|
-00000050 56 4e d6 02 14 1a ed 03 87 ad d1 3e f1 5d 41 c5 |VN.........>.]A.|
-00000060 c0 fe 8e ce 6c c2 ce 2e 4a f6 4f a0 f9 d7 a9 2d |....l...J.O....-|
-00000070 22 62 78 5a a6 cb bb 62 98 20 fe f6 3d d3 b6 f8 |"bxZ...b. ..=...|
-00000080 7f 1a 5a e5 59 32 93 bd f0 82 e5 14 03 03 00 01 |..Z.Y2..........|
-00000090 01 16 03 03 00 40 96 3c c7 3f 87 d7 2e fb fb 2f |.....@.<.?...../|
-000000a0 a0 0f 60 fc a9 9c 27 c2 0d e0 a6 f9 76 8c 94 59 |..`...'.....v..Y|
-000000b0 02 ae 5c a3 b2 20 6f c7 a5 a3 ad 98 87 cf 29 02 |..\.. o.......).|
-000000c0 87 ce db 09 ee b7 eb f4 81 59 37 13 15 5b 91 fe |.........Y7..[..|
-000000d0 e7 b3 6f 69 fd d2 |..oi..|
+00000000 16 03 03 00 86 10 00 00 82 00 80 2c d6 6d 84 0c |...........,.m..|
+00000010 d9 ef 52 bb cc 0b 41 47 d7 64 c7 a6 b0 fa 3c 6f |..R...AG.d....<o|
+00000020 c3 31 95 bc ab 4b c6 72 45 ef fb 49 6f fc 5c 63 |.1...K.rE..Io.\c|
+00000030 48 d6 db 97 3b 9e 8b d9 a6 f4 59 ae 27 07 6d 1d |H...;.....Y.'.m.|
+00000040 3b 56 72 a7 5c 6f 9d 84 e2 ea ed e9 ce 8a d1 9f |;Vr.\o..........|
+00000050 bf b6 89 c9 36 be 76 cb 3f f2 40 7d b6 b8 af 4c |....6.v.?.@}...L|
+00000060 35 85 40 b8 02 7b 53 0a 33 21 fa 49 ce af 85 27 |5.@..{S.3!.I...'|
+00000070 7f ae 03 ec a2 62 5a e3 f3 41 d5 bd 8e dc e8 81 |.....bZ..A......|
+00000080 79 f0 63 95 47 bf a0 55 22 4f 42 14 03 03 00 01 |y.c.G..U"OB.....|
+00000090 01 16 03 03 00 40 63 27 d9 ca 1e 88 7d 52 6a 2c |.....@c'....}Rj,|
+000000a0 06 db f7 db 18 28 ec 4b ff 57 76 8c 3b 3d de a7 |.....(.K.Wv.;=..|
+000000b0 7b 11 75 59 61 69 3d 6d 5a 90 c4 3b b4 a7 e8 38 |{.uYai=mZ..;...8|
+000000c0 81 06 96 ca af c0 5b 42 ba 05 4b 61 82 dd eb 04 |......[B..Ka....|
+000000d0 07 81 7a 58 30 a4 |..zX0.|
>>> Flow 4 (server to client)
-00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c 9f 83 61 5c 5f 43 13 c2 76 91 3a c1 1a 8c |o,..a\_C..v.:...|
-00000040 51 00 5c a0 93 a9 06 e2 0c b0 65 e3 8c 0d 4b 7b |Q.\.......e...K{|
-00000050 7e 52 32 b8 3c b3 76 c5 bf 95 4d 29 71 50 81 e3 |~R2.<.v...M)qP..|
-00000060 2b 6f 4a 32 dc 33 94 15 c5 fe 38 b4 0a fc 03 38 |+oJ2.3....8....8|
-00000070 90 32 db c0 7f 99 62 a9 89 15 d0 f6 79 64 79 38 |.2....b.....ydy8|
-00000080 b0 e2 19 07 82 82 0a 14 03 03 00 01 01 16 03 03 |................|
-00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............|
-000000a0 00 00 69 6f c8 63 ce 7b d5 82 6e f8 5f 59 ab ad |..io.c.{..n._Y..|
-000000b0 55 0c 76 8b 11 56 77 ea 33 20 fd 0b 33 9d 72 12 |U.v..Vw.3 ..3.r.|
-000000c0 85 fe 99 38 2a 70 49 fe 27 35 9d 43 5b 32 2b 77 |...8*pI.'5.C[2+w|
-000000d0 31 66 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |1f....@.........|
-000000e0 00 00 00 00 00 00 00 05 36 d1 49 58 00 4d 5c bc |........6.IX.M\.|
-000000f0 a8 c4 be 76 5d f7 cc 88 c7 5a 44 8c f6 d0 30 e6 |...v]....ZD...0.|
-00000100 87 03 84 77 60 6c 47 70 2a 80 51 38 a8 8a fb 9f |...w`lGp*.Q8....|
-00000110 31 45 f0 ab c9 e5 94 15 03 03 00 30 00 00 00 00 |1E.........0....|
-00000120 00 00 00 00 00 00 00 00 00 00 00 00 19 f0 c7 ce |................|
-00000130 92 87 25 dd 5b c3 68 3b dd ec 5c 26 c6 90 36 31 |..%.[.h;..\&..61|
-00000140 a5 3c 9a 89 be 49 30 37 3b a5 5f 13 |.<...I07;._.|
+00000030 6f 2c 9f 83 51 ed 14 ef 68 ca 42 c5 4c 92 cc 13 |o,..Q...h.B.L...|
+00000040 05 4e 15 de 98 0a 74 d5 a9 2e 80 89 98 89 72 39 |.N....t.......r9|
+00000050 5f fe 49 56 66 ac 4d 73 b1 5b 4b 81 db 25 a7 5b |_.IVf.Ms.[K..%.[|
+00000060 54 5b 10 13 3d 96 71 d7 b7 23 53 ea 62 49 38 16 |T[..=.q..#S.bI8.|
+00000070 cc 4f 0d 9d 80 99 6e 0f 01 b3 d7 e4 8a 75 d1 b6 |.O....n......u..|
+00000080 7b 74 80 b2 b8 06 a9 71 6b 31 2a fd cf 6e 44 dc |{t.....qk1*..nD.|
+00000090 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+000000a0 00 00 00 00 00 00 00 00 00 00 00 76 c4 85 3d 05 |...........v..=.|
+000000b0 60 a2 b3 ce 38 7f 1c f9 e3 19 87 b0 e1 af 08 b7 |`...8...........|
+000000c0 15 90 50 b9 51 85 c4 88 90 52 cd 6d b6 69 ee b5 |..P.Q....R.m.i..|
+000000d0 36 a8 0c 61 c4 78 09 6a 49 4d e9 17 03 03 00 40 |6..a.x.jIM.....@|
+000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000f0 76 31 e3 05 f8 b3 05 ca e2 55 84 b9 15 85 5d 4a |v1.......U....]J|
+00000100 83 a5 76 db b0 5f b9 65 b4 21 3e 00 36 9a e8 d7 |..v.._.e.!>.6...|
+00000110 02 81 23 83 19 13 c8 9c cd 02 ae 10 b9 cf 75 96 |..#...........u.|
+00000120 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000130 00 00 00 00 00 f9 ae b4 16 27 75 dc 72 4d 39 0e |.........'u.rM9.|
+00000140 ba 1f 31 b2 39 ec 99 36 bc 41 34 03 54 9b de 7b |..1.9..6.A4.T..{|
+00000150 4b 65 ef 99 a6 |Ke...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
index cc1b6b0173..c50fbcedf7 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -1,92 +1,91 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 00 9b 01 00 00 97 03 03 55 4e 24 f5 fd |...........UN$..|
-00000010 2b 70 d1 b4 9c fd eb 53 1d 2f 7e f7 59 fe 20 c6 |+p.....S./~.Y. .|
-00000020 4f 47 72 0f 7a 01 71 48 8a 21 9a 00 00 04 00 2f |OGr.z.qH.!...../|
-00000030 00 ff 01 00 00 6a 00 00 00 0e 00 0c 00 00 09 31 |.....j.........1|
-00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
-00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
-00000060 00 23 00 00 00 16 00 00 00 17 00 00 00 0d 00 30 |.#.............0|
-00000070 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 08 0a |................|
-00000080 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 03 03 |................|
-00000090 02 03 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |................|
+00000000 16 03 01 00 71 01 00 00 6d 03 03 98 eb fe 13 a7 |....q...m.......|
+00000010 81 d8 8b 0b c6 78 c3 44 ce f7 7b 63 d1 7c 61 4d |.....x.D..{c.|aM|
+00000020 be fe 52 5f c0 24 88 c2 85 d1 40 00 00 04 00 2f |..R_.$....@..../|
+00000030 00 ff 01 00 00 40 00 23 00 00 00 16 00 00 00 17 |.....@.#........|
+00000040 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+00000050 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+00000060 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+00000070 04 02 05 02 06 02 |......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
-00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
-00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
-00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
-00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
-00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
-00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
-00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
-000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
-000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
-000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
-000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
-000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
-000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
-00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
-00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
-00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
-00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
-00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
-00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
-00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
-00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
-00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
-00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
-000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
-000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
-000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
-000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
-000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
-000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
-00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
-00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
-00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
-00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
-00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
-00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
-00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
-00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
-00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
-00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
-000002a0 03 00 04 0e 00 00 00 |.......|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
>>> Flow 3 (client to server)
-00000000 16 03 03 00 86 10 00 00 82 00 80 29 31 85 e2 ce |...........)1...|
-00000010 42 63 7f 16 3a 0b 67 19 64 da bb 7a bc fe c7 a9 |Bc..:.g.d..z....|
-00000020 fb f1 d0 c1 7e 3d 2e 69 f8 97 43 7e 73 8a eb 9a |....~=.i..C~s...|
-00000030 e4 f4 d0 e8 93 47 ec c1 89 a0 d3 93 65 47 1c 33 |.....G......eG.3|
-00000040 75 af 90 07 bb 46 27 09 c6 0c 4f 43 10 87 c9 a6 |u....F'...OC....|
-00000050 da 58 02 a7 61 4b 67 40 05 72 9b 07 aa 9b 04 18 |.X..aKg@.r......|
-00000060 6a 35 d1 54 f8 fc 08 f5 9f 49 8d aa aa 4c 2c bf |j5.T.....I...L,.|
-00000070 55 85 ed 6b ae 7e cd 77 a2 9b e3 a7 03 8d 9e d9 |U..k.~.w........|
-00000080 12 12 ce 1c c4 ba 10 f3 d5 f4 c2 14 03 03 00 01 |................|
-00000090 01 16 03 03 00 40 2c 57 5d 8b 73 4f 31 ed 16 e5 |.....@,W].sO1...|
-000000a0 17 bd 08 a9 26 95 51 0d f6 0c 82 af f2 26 9e 5e |....&.Q......&.^|
-000000b0 31 71 e5 7c dc 41 62 10 da d5 20 f1 dc 00 ea 25 |1q.|.Ab... ....%|
-000000c0 5a 4b 15 e1 ba 46 c1 5f 64 a6 59 58 55 2a 01 41 |ZK...F._d.YXU*.A|
-000000d0 3e 6b 22 b8 79 27 |>k".y'|
+00000000 16 03 03 00 86 10 00 00 82 00 80 11 4c a1 a0 ba |............L...|
+00000010 12 83 63 98 3c 1a 5d df a2 01 b6 6c 05 ec a1 1e |..c.<.]....l....|
+00000020 dc a5 6b b9 97 c3 76 51 06 45 4b 74 9e 1b 61 0f |..k...vQ.EKt..a.|
+00000030 9e d3 c7 db 7f d3 ee 23 1a 32 66 0f 2f 2c d3 52 |.......#.2f./,.R|
+00000040 e0 ec cc 31 71 d4 e6 2b b6 95 78 0b eb c9 70 b1 |...1q..+..x...p.|
+00000050 77 09 6f 8d 6d 8d 1b d7 b2 38 96 d3 f0 a2 94 37 |w.o.m....8.....7|
+00000060 14 ed d8 d6 b5 1e bc 71 b2 35 68 76 5b 10 dc 8f |.......q.5hv[...|
+00000070 de 9d 1d b5 59 d0 f1 04 70 9b 74 a9 af 7f b6 6b |....Y...p.t....k|
+00000080 de 29 5a fd 8f 95 cd 2c d6 b9 18 14 03 03 00 01 |.)Z....,........|
+00000090 01 16 03 03 00 40 02 70 cb 83 3c 42 32 58 9f 05 |.....@.p..<B2X..|
+000000a0 36 b7 3b 47 1d 58 ec cf 3f 2a ae 23 ac e6 d0 4c |6.;G.X..?*.#...L|
+000000b0 91 53 0f e8 7c c9 19 a9 e9 1c 6d fc 21 bd a0 51 |.S..|.....m.!..Q|
+000000c0 0a b2 f5 9d 34 22 30 24 bc fe 44 e0 b2 23 51 9d |....4"0$..D..#Q.|
+000000d0 c5 a8 d4 60 a3 bd |...`..|
>>> Flow 4 (server to client)
-00000000 16 03 03 00 82 04 00 00 7e 00 00 00 00 00 78 50 |........~.....xP|
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
-00000030 6f 2c 9f 83 61 31 33 93 70 cd 6a 19 a2 67 e8 7d |o,..a13.p.j..g.}|
-00000040 cb a4 dc bb 80 d9 23 20 05 4d 53 1f b6 9f 48 01 |......# .MS...H.|
-00000050 e4 84 75 10 25 f9 ed 98 bb 39 7e fc 8b 16 d8 bc |..u.%....9~.....|
-00000060 c7 e9 88 e8 1c 33 94 10 13 6b d4 3d fa d7 73 b2 |.....3...k.=..s.|
-00000070 d4 ea 89 58 ed 38 f8 f3 6a e0 5f 1e f7 49 ed f7 |...X.8..j._..I..|
-00000080 5f 64 39 6b b5 6c fb 14 03 03 00 01 01 16 03 03 |_d9k.l..........|
-00000090 00 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |.@..............|
-000000a0 00 00 fa f3 aa 48 54 5f 5b 88 69 fb 01 75 2a 90 |.....HT_[.i..u*.|
-000000b0 49 46 7c 6a 3a aa 72 4e 35 db 8f 38 a3 4d 05 53 |IF|j:.rN5..8.M.S|
-000000c0 38 93 63 ae 0d b9 e0 b4 81 2e ee 40 d5 2b 58 2a |8.c........@.+X*|
-000000d0 18 9b 17 03 03 00 40 00 00 00 00 00 00 00 00 00 |......@.........|
-000000e0 00 00 00 00 00 00 00 3c 84 3f 45 03 b0 60 ed 8f |.......<.?E..`..|
-000000f0 d2 e5 10 98 03 1a 00 8a aa 19 d0 e9 03 fb 42 fc |..............B.|
-00000100 cd 4d 13 3e 7d 39 0b 5f cf 2d b7 87 3a bf 43 d4 |.M.>}9._.-..:.C.|
-00000110 ac 71 68 29 bf f8 ac 15 03 03 00 30 00 00 00 00 |.qh).......0....|
-00000120 00 00 00 00 00 00 00 00 00 00 00 00 81 49 eb 3b |.............I.;|
-00000130 28 e7 88 94 8b 6a cc 67 4d c4 03 66 80 af d7 c2 |(....j.gM..f....|
-00000140 07 37 36 3b f0 a4 5d 16 2b 5f 5b 27 |.76;..].+_['|
+00000030 6f 2c 9f 83 51 ed 14 ef 68 ca 42 c5 4c 3e 73 fe |o,..Q...h.B.L>s.|
+00000040 72 ef 06 25 96 ef 3d 89 51 22 e3 10 57 02 e5 69 |r..%..=.Q"..W..i|
+00000050 aa d0 6d ad 66 b3 4c 07 fc ba a4 1e 3a ad a2 3b |..m.f.L.....:..;|
+00000060 40 f7 7d 9a 11 8e a0 9e 54 c5 7c 53 7d 49 38 16 |@.}.....T.|S}I8.|
+00000070 43 a6 1b 37 8e aa 02 78 25 9b 06 54 13 54 de 6a |C..7...x%..T.T.j|
+00000080 ae 62 72 97 47 1d f8 0a 32 c3 86 93 0e 64 cc 04 |.br.G...2....d..|
+00000090 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+000000a0 00 00 00 00 00 00 00 00 00 00 00 ac 24 92 7d 6c |............$.}l|
+000000b0 d5 fe a8 a7 b7 45 fe 58 f6 13 02 ed de c8 ba 44 |.....E.X.......D|
+000000c0 18 59 1e f9 06 82 2f 42 22 62 5a 82 4d 70 9a c3 |.Y..../B"bZ.Mp..|
+000000d0 41 55 b0 66 ae e2 b1 1d d9 38 0a 17 03 03 00 40 |AU.f.....8.....@|
+000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000f0 bd 16 9e 9c f2 9b 0d f8 f1 42 ba f3 38 64 69 ac |.........B..8di.|
+00000100 4a c9 25 d7 03 0b ec 8f 53 14 26 68 da b7 43 34 |J.%.....S.&h..C4|
+00000110 18 cd 66 dc 36 5e f5 16 ca 18 78 37 89 8a d5 9d |..f.6^....x7....|
+00000120 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000130 00 00 00 00 00 64 f9 5c df db 60 b7 22 15 77 29 |.....d.\..`.".w)|
+00000140 33 6f 93 22 81 c4 e5 71 af 27 60 e5 76 5f a6 f6 |3o."...q.'`.v_..|
+00000150 e0 73 87 9f ed |.s...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
index d1dba66d82..e8205b743d 100644
--- a/src/crypto/tls/testdata/Server-TLSv12-Resume
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -1,48 +1,46 @@
>>> Flow 1 (client to server)
-00000000 16 03 01 01 33 01 00 01 2f 03 03 c0 ac ee 47 eb |....3.../.....G.|
-00000010 75 70 12 a9 b7 d9 29 03 ba dd 0c 26 ef 07 cd c1 |up....)....&....|
-00000020 ac 2b b5 14 8a 59 3a d7 58 7d 20 20 eb 74 37 f4 |.+...Y:.X} .t7.|
-00000030 79 3b 34 ed e4 b1 51 00 b9 09 04 bc 48 82 07 a2 |y;4...Q.....H...|
-00000040 cc 47 2d dc 16 54 a6 02 0c 5e f2 23 00 04 00 2f |.G-..T...^.#.../|
-00000050 00 ff 01 00 00 e2 00 00 00 0e 00 0c 00 00 09 31 |...............1|
-00000060 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
-00000070 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
-00000080 00 23 00 78 50 46 ad c1 db a8 38 86 7b 2b bb fd |.#.xPF....8.{+..|
-00000090 d0 c3 42 3e 00 00 00 00 00 00 00 00 00 00 00 00 |..B>............|
-000000a0 00 00 00 00 94 6f 2c 9f 83 61 5c 5f 43 13 c2 76 |.....o,..a\_C..v|
-000000b0 91 3a c1 1a 8c 51 00 5c a0 93 a9 06 e2 0c b0 65 |.:...Q.\.......e|
-000000c0 e3 8c 0d 4b 7b 7e 52 32 b8 3c b3 76 c5 bf 95 4d |...K{~R2.<.v...M|
-000000d0 29 71 50 81 e3 2b 6f 4a 32 dc 33 94 15 c5 fe 38 |)qP..+oJ2.3....8|
-000000e0 b4 0a fc 03 38 90 32 db c0 7f 99 62 a9 89 15 d0 |....8.2....b....|
-000000f0 f6 79 64 79 38 b0 e2 19 07 82 82 0a 00 16 00 00 |.ydy8...........|
-00000100 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 |.......0........|
-00000110 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 |................|
-00000120 04 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 |................|
-00000130 02 02 04 02 05 02 06 02 |........|
+00000000 16 03 01 01 12 01 00 01 0e 03 03 3e 4f b2 97 44 |...........>O..D|
+00000010 64 a4 e1 33 32 21 98 ea c1 8c 3f 7b 5f 47 e6 54 |d..32!....?{_G.T|
+00000020 bf f1 a9 fd fb 5c 1e c9 23 7a 12 20 42 f6 4f a1 |.....\..#z. B.O.|
+00000030 85 90 ad 50 2b 3b 24 f7 2e 48 1f 2d 5b 0d fe 77 |...P+;$..H.-[..w|
+00000040 07 2b cb e9 03 23 d9 24 04 05 4e 26 00 04 00 2f |.+...#.$..N&.../|
+00000050 00 ff 01 00 00 c1 00 23 00 81 50 46 ad c1 db a8 |.......#..PF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 51 |...........o,..Q|
+00000080 ed 14 ef 68 ca 42 c5 4c 92 cc 13 05 4e 15 de 98 |...h.B.L....N...|
+00000090 0a 74 d5 a9 2e 80 89 98 89 72 39 5f fe 49 56 66 |.t.......r9_.IVf|
+000000a0 ac 4d 73 b1 5b 4b 81 db 25 a7 5b 54 5b 10 13 3d |.Ms.[K..%.[T[..=|
+000000b0 96 71 d7 b7 23 53 ea 62 49 38 16 cc 4f 0d 9d 80 |.q..#S.bI8..O...|
+000000c0 99 6e 0f 01 b3 d7 e4 8a 75 d1 b6 7b 74 80 b2 b8 |.n......u..{t...|
+000000d0 06 a9 71 6b 31 2a fd cf 6e 44 dc 00 16 00 00 00 |..qk1*..nD......|
+000000e0 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 |......0.........|
+000000f0 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 |................|
+00000100 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 |................|
+00000110 02 04 02 05 02 06 02 |.......|
>>> Flow 2 (server to client)
-00000000 16 03 03 00 57 02 00 00 53 03 03 00 00 00 00 00 |....W...S.......|
+00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
-00000020 00 00 00 44 4f 57 4e 47 52 44 01 20 eb 74 37 f4 |...DOWNGRD. .t7.|
-00000030 79 3b 34 ed e4 b1 51 00 b9 09 04 bc 48 82 07 a2 |y;4...Q.....H...|
-00000040 cc 47 2d dc 16 54 a6 02 0c 5e f2 23 00 2f 00 00 |.G-..T...^.#./..|
-00000050 0b ff 01 00 01 00 00 0b 00 02 01 00 14 03 03 00 |................|
-00000060 01 01 16 03 03 00 40 00 00 00 00 00 00 00 00 00 |......@.........|
-00000070 00 00 00 00 00 00 00 a6 49 4b 9d e0 3c e1 58 b4 |........IK..<.X.|
-00000080 f9 50 e6 a6 32 ce 65 74 14 95 07 05 0c ef be 7d |.P..2.et.......}|
-00000090 74 8c 46 3e 2a 07 de 5f 7a 08 b9 a0 80 f0 52 90 |t.F>*.._z.....R.|
-000000a0 d4 6b c5 0f c5 ae 54 |.k....T|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 20 42 f6 4f a1 |...DOWNGRD. B.O.|
+00000030 85 90 ad 50 2b 3b 24 f7 2e 48 1f 2d 5b 0d fe 77 |...P+;$..H.-[..w|
+00000040 07 2b cb e9 03 23 d9 24 04 05 4e 26 00 2f 00 00 |.+...#.$..N&./..|
+00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
+00000060 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
+00000070 00 dc 9b ca 90 7b f0 70 bc 17 76 9c fb a7 74 49 |.....{.p..v...tI|
+00000080 0c 9f 3c 31 76 77 9b af 6a e0 00 a6 54 81 4a d5 |..<1vw..j...T.J.|
+00000090 de fa 75 cb d6 b4 b2 6c bc f4 30 7a a1 56 0a f5 |..u....l..0z.V..|
+000000a0 5c |\|
>>> Flow 3 (client to server)
-00000000 14 03 03 00 01 01 16 03 03 00 40 8c 59 48 06 01 |..........@.YH..|
-00000010 a4 c6 35 ad a6 f5 a9 d3 31 ea 58 64 0e 45 91 4c |..5.....1.Xd.E.L|
-00000020 fb e7 c6 6e 27 e8 92 a9 9c c3 c6 29 e9 6c 55 3a |...n'......).lU:|
-00000030 2a fe 0f 40 d9 aa 3e fe ab 66 e1 38 91 d1 db ac |*..@..>..f.8....|
-00000040 58 13 f0 3c 5e f1 a9 9c fd 07 04 |X..<^......|
+00000000 14 03 03 00 01 01 16 03 03 00 40 cb 74 dc ec f5 |..........@.t...|
+00000010 ad ab c5 8e dc da 50 89 28 7b cc 0f 06 87 9a 19 |......P.({......|
+00000020 dd 4e 40 38 1d 8f 95 6f 0e 62 5f cb 7c db ab 24 |.N@8...o.b_.|..$|
+00000030 df 03 ef 7c 83 12 0e 3d 25 e8 de cf d0 aa 0e 91 |...|...=%.......|
+00000040 20 9b 38 39 4e 39 70 3c 0a ce c8 | .89N9p<...|
>>> Flow 4 (server to client)
00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
-00000010 00 00 00 00 00 a6 4f 7a f8 b0 6e 25 13 fb b6 68 |......Oz..n%...h|
-00000020 2d 1e 22 1b 95 93 63 e8 e1 9c 93 3e 53 78 bb aa |-."...c....>Sx..|
-00000030 9f 6e 84 56 28 31 a0 ed a9 a3 06 fd e6 f9 c4 c4 |.n.V(1..........|
-00000040 56 5f 5f c2 fb 15 03 03 00 30 00 00 00 00 00 00 |V__......0......|
-00000050 00 00 00 00 00 00 00 00 00 00 c9 98 24 06 26 73 |............$.&s|
-00000060 87 27 73 bd 7a 30 b5 85 28 f7 c4 b6 7a b0 96 9f |.'s.z0..(...z...|
-00000070 a8 d4 43 1d 8e f5 a5 9f f3 f3 |..C.......|
+00000010 00 00 00 00 00 d1 5b 42 2c 10 9b 48 97 cf 8e 69 |......[B,..H...i|
+00000020 a4 b4 62 65 d9 f1 1f 86 07 f1 6c cd 5b 18 6e c7 |..be......l.[.n.|
+00000030 8d 57 20 3d f9 3f 68 1b 12 7b 29 13 b9 8d fe 7b |.W =.?h..{)....{|
+00000040 ad 52 22 c4 94 15 03 03 00 30 00 00 00 00 00 00 |.R"......0......|
+00000050 00 00 00 00 00 00 00 00 00 00 31 ae ae 06 b7 2c |..........1....,|
+00000060 5f a4 fc 8f a6 33 2b 42 1a f5 d5 b9 ad a4 fc a0 |_....3+B........|
+00000070 bc e9 c8 5d 4d 26 83 38 ca 57 |...]M&.8.W|
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
index dda0443ff4..6c1d20da20 100644
--- a/src/crypto/tls/ticket.go
+++ b/src/crypto/tls/ticket.go
@@ -22,9 +22,10 @@ import (
type sessionState struct {
vers uint16
cipherSuite uint16
+ createdAt uint64
masterSecret []byte // opaque master_secret<1..2^16-1>;
- // struct { opaque certificate<1..2^32-1> } Certificate;
- certificates [][]byte // Certificate certificate_list<0..2^16-1>;
+ // struct { opaque certificate<1..2^24-1> } Certificate;
+ certificates [][]byte // Certificate certificate_list<0..2^24-1>;
// usedOldKey is true if the ticket from which this session came from
// was encrypted with an older key and thus should be refreshed.
@@ -35,12 +36,13 @@ func (m *sessionState) marshal() []byte {
var b cryptobyte.Builder
b.AddUint16(m.vers)
b.AddUint16(m.cipherSuite)
+ addUint64(&b, m.createdAt)
b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(m.masterSecret)
})
- b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
for _, cert := range m.certificates {
- b.AddUint32LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
b.AddBytes(cert)
})
}
@@ -52,21 +54,19 @@ func (m *sessionState) unmarshal(data []byte) bool {
*m = sessionState{usedOldKey: m.usedOldKey}
s := cryptobyte.String(data)
if ok := s.ReadUint16(&m.vers) &&
- m.vers != VersionTLS13 &&
s.ReadUint16(&m.cipherSuite) &&
+ readUint64(&s, &m.createdAt) &&
readUint16LengthPrefixed(&s, &m.masterSecret) &&
len(m.masterSecret) != 0; !ok {
return false
}
var certList cryptobyte.String
- if !s.ReadUint16LengthPrefixed(&certList) {
+ if !s.ReadUint24LengthPrefixed(&certList) {
return false
}
for !certList.Empty() {
- var certLen uint32
- certList.ReadUint32(&certLen)
var cert []byte
- if certLen == 0 || !certList.ReadBytes(&cert, int(certLen)) {
+ if !readUint24LengthPrefixed(&certList, &cert) {
return false
}
m.certificates = append(m.certificates, cert)
@@ -117,6 +117,10 @@ func (m *sessionStateTLS13) unmarshal(data []byte) bool {
}
func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
+ if len(c.ticketKeys) == 0 {
+ return nil, errors.New("tls: internal error: session ticket keys unavailable")
+ }
+
encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
keyName := encrypted[:ticketKeyNameLen]
iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
@@ -125,7 +129,7 @@ func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
return nil, err
}
- key := c.config.ticketKeys()[0]
+ key := c.ticketKeys[0]
copy(keyName, key.keyName[:])
block, err := aes.NewCipher(key.aesKey[:])
if err != nil {
@@ -150,19 +154,17 @@ func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey boo
macBytes := encrypted[len(encrypted)-sha256.Size:]
ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
- keys := c.config.ticketKeys()
keyIndex := -1
- for i, candidateKey := range keys {
+ for i, candidateKey := range c.ticketKeys {
if bytes.Equal(keyName, candidateKey.keyName[:]) {
keyIndex = i
break
}
}
-
if keyIndex == -1 {
return nil, false
}
- key := &keys[keyIndex]
+ key := &c.ticketKeys[keyIndex]
mac := hmac.New(sha256.New, key.hmacKey[:])
mac.Write(encrypted[:len(encrypted)-sha256.Size])
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
index 36d98d39eb..1c5173e281 100644
--- a/src/crypto/tls/tls.go
+++ b/src/crypto/tls/tls.go
@@ -235,7 +235,7 @@ func (d *Dialer) netDialer() *net.Dialer {
return new(net.Dialer)
}
-// Dial connects to the given network address and initiates a TLS
+// DialContext connects to the given network address and initiates a TLS
// handshake, returning the resulting TLS connection.
//
// The provided Context must be non-nil. If the context expires before
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
index 85005d4950..d5238026da 100644
--- a/src/crypto/tls/tls_test.go
+++ b/src/crypto/tls/tls_test.go
@@ -734,7 +734,7 @@ func TestWarningAlertFlood(t *testing.T) {
}
func TestCloneFuncFields(t *testing.T) {
- const expectedCount = 5
+ const expectedCount = 6
called := 0
c1 := Config{
@@ -758,6 +758,10 @@ func TestCloneFuncFields(t *testing.T) {
called |= 1 << 4
return nil
},
+ VerifyConnection: func(ConnectionState) error {
+ called |= 1 << 5
+ return nil
+ },
}
c2 := c1.Clone()
@@ -767,6 +771,7 @@ func TestCloneFuncFields(t *testing.T) {
c2.GetClientCertificate(nil)
c2.GetConfigForClient(nil)
c2.VerifyPeerCertificate(nil, nil)
+ c2.VerifyConnection(ConnectionState{})
if called != (1<<expectedCount)-1 {
t.Fatalf("expected %d calls but saw calls %b", expectedCount, called)
@@ -780,17 +785,12 @@ func TestCloneNonFuncFields(t *testing.T) {
typ := v.Type()
for i := 0; i < typ.NumField(); i++ {
f := v.Field(i)
- if !f.CanSet() {
- // unexported field; not cloned.
- continue
- }
-
// testing/quick can't handle functions or interfaces and so
// isn't used here.
switch fn := typ.Field(i).Name; fn {
case "Rand":
f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
- case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "GetClientCertificate":
+ case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "VerifyConnection", "GetClientCertificate":
// DeepEqual can't compare functions. If you add a
// function field to this list, you must also change
// TestCloneFuncFields to ensure that the func field is
@@ -825,17 +825,17 @@ func TestCloneNonFuncFields(t *testing.T) {
f.Set(reflect.ValueOf([]CurveID{CurveP256}))
case "Renegotiation":
f.Set(reflect.ValueOf(RenegotiateOnceAsClient))
+ case "mutex", "autoSessionTicketKeys", "sessionTicketKeys":
+ continue // these are unexported fields that are handled separately
default:
t.Errorf("all fields must be accounted for, but saw unknown field %q", fn)
}
}
+ // Set the unexported fields related to session ticket keys, which are copied with Clone().
+ c1.autoSessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
+ c1.sessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
c2 := c1.Clone()
- // DeepEqual also compares unexported fields, thus c2 needs to have run
- // serverInit in order to be DeepEqual to c1. Cloning it and discarding
- // the result is sufficient.
- c2.Clone()
-
if !reflect.DeepEqual(&c1, c2) {
t.Errorf("clone failed to copy a field")
}
@@ -1116,8 +1116,8 @@ func TestConnectionState(t *testing.T) {
if ss.ServerName != serverName {
t.Errorf("Got server name %q, expected %q", ss.ServerName, serverName)
}
- if cs.ServerName != "" {
- t.Errorf("Got unexpected server name on the client side")
+ if cs.ServerName != serverName {
+ t.Errorf("Got server name on client connection %q, expected %q", cs.ServerName, serverName)
}
if len(ss.PeerCertificates) != 1 || len(cs.PeerCertificates) != 1 {
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
index 3e1e5fb8cd..59ec4b6894 100644
--- a/src/crypto/x509/cert_pool.go
+++ b/src/crypto/x509/cert_pool.go
@@ -47,11 +47,15 @@ func (s *CertPool) copy() *CertPool {
// SystemCertPool returns a copy of the system cert pool.
//
-// Any mutations to the returned pool are not written to disk and do
-// not affect any other pool returned by SystemCertPool.
+// On Unix systems other than macOS the environment variables SSL_CERT_FILE and
+// SSL_CERT_DIR can be used to override the system default locations for the SSL
+// certificate file and SSL certificate files directory, respectively. The
+// latter can be a colon-separated list.
//
-// New changes in the system cert pool might not be reflected
-// in subsequent calls.
+// Any mutations to the returned pool are not written to disk and do not affect
+// any other pool returned by SystemCertPool.
+//
+// New changes in the system cert pool might not be reflected in subsequent calls.
func SystemCertPool() (*CertPool, error) {
if runtime.GOOS == "windows" {
// Issue 16736, 18609:
diff --git a/src/crypto/x509/internal/macOS/corefoundation.go b/src/crypto/x509/internal/macOS/corefoundation.go
new file mode 100644
index 0000000000..359694fabf
--- /dev/null
+++ b/src/crypto/x509/internal/macOS/corefoundation.go
@@ -0,0 +1,141 @@
+// Copyright 2020 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,amd64
+
+// Package macOS provides cgo-less wrappers for Core Foundation and
+// Security.framework, similarly to how package syscall provides access to
+// libSystem.dylib.
+package macOS
+
+import (
+ "errors"
+ "reflect"
+ "runtime"
+ "unsafe"
+)
+
+// CFRef is an opaque reference to a Core Foundation object. It is a pointer,
+// but to memory not owned by Go, so not an unsafe.Pointer.
+type CFRef uintptr
+
+// CFDataToSlice returns a copy of the contents of data as a bytes slice.
+func CFDataToSlice(data CFRef) []byte {
+ length := CFDataGetLength(data)
+ ptr := CFDataGetBytePtr(data)
+ src := (*[1 << 20]byte)(unsafe.Pointer(ptr))[:length:length]
+ out := make([]byte, length)
+ copy(out, src)
+ return out
+}
+
+type CFString CFRef
+
+const kCFAllocatorDefault = 0
+const kCFStringEncodingUTF8 = 0x08000100
+
+//go:linkname x509_CFStringCreateWithBytes x509_CFStringCreateWithBytes
+//go:cgo_import_dynamic x509_CFStringCreateWithBytes CFStringCreateWithBytes "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+// StringToCFString returns a copy of the UTF-8 contents of s as a new CFString.
+func StringToCFString(s string) CFString {
+ p := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&s)).Data)
+ ret := syscall(funcPC(x509_CFStringCreateWithBytes_trampoline), kCFAllocatorDefault, uintptr(p),
+ uintptr(len(s)), uintptr(kCFStringEncodingUTF8), 0 /* isExternalRepresentation */, 0)
+ runtime.KeepAlive(p)
+ return CFString(ret)
+}
+func x509_CFStringCreateWithBytes_trampoline()
+
+//go:linkname x509_CFDictionaryGetValueIfPresent x509_CFDictionaryGetValueIfPresent
+//go:cgo_import_dynamic x509_CFDictionaryGetValueIfPresent CFDictionaryGetValueIfPresent "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDictionaryGetValueIfPresent(dict CFRef, key CFString) (value CFRef, ok bool) {
+ ret := syscall(funcPC(x509_CFDictionaryGetValueIfPresent_trampoline), uintptr(dict), uintptr(key),
+ uintptr(unsafe.Pointer(&value)), 0, 0, 0)
+ if ret == 0 {
+ return 0, false
+ }
+ return value, true
+}
+func x509_CFDictionaryGetValueIfPresent_trampoline()
+
+const kCFNumberSInt32Type = 3
+
+//go:linkname x509_CFNumberGetValue x509_CFNumberGetValue
+//go:cgo_import_dynamic x509_CFNumberGetValue CFNumberGetValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFNumberGetValue(num CFRef) (int32, error) {
+ var value int32
+ ret := syscall(funcPC(x509_CFNumberGetValue_trampoline), uintptr(num), uintptr(kCFNumberSInt32Type),
+ uintptr(unsafe.Pointer(&value)), 0, 0, 0)
+ if ret == 0 {
+ return 0, errors.New("CFNumberGetValue call failed")
+ }
+ return value, nil
+}
+func x509_CFNumberGetValue_trampoline()
+
+//go:linkname x509_CFDataGetLength x509_CFDataGetLength
+//go:cgo_import_dynamic x509_CFDataGetLength CFDataGetLength "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDataGetLength(data CFRef) int {
+ ret := syscall(funcPC(x509_CFDataGetLength_trampoline), uintptr(data), 0, 0, 0, 0, 0)
+ return int(ret)
+}
+func x509_CFDataGetLength_trampoline()
+
+//go:linkname x509_CFDataGetBytePtr x509_CFDataGetBytePtr
+//go:cgo_import_dynamic x509_CFDataGetBytePtr CFDataGetBytePtr "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDataGetBytePtr(data CFRef) uintptr {
+ ret := syscall(funcPC(x509_CFDataGetBytePtr_trampoline), uintptr(data), 0, 0, 0, 0, 0)
+ return ret
+}
+func x509_CFDataGetBytePtr_trampoline()
+
+//go:linkname x509_CFArrayGetCount x509_CFArrayGetCount
+//go:cgo_import_dynamic x509_CFArrayGetCount CFArrayGetCount "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayGetCount(array CFRef) int {
+ ret := syscall(funcPC(x509_CFArrayGetCount_trampoline), uintptr(array), 0, 0, 0, 0, 0)
+ return int(ret)
+}
+func x509_CFArrayGetCount_trampoline()
+
+//go:linkname x509_CFArrayGetValueAtIndex x509_CFArrayGetValueAtIndex
+//go:cgo_import_dynamic x509_CFArrayGetValueAtIndex CFArrayGetValueAtIndex "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayGetValueAtIndex(array CFRef, index int) CFRef {
+ ret := syscall(funcPC(x509_CFArrayGetValueAtIndex_trampoline), uintptr(array), uintptr(index), 0, 0, 0, 0)
+ return CFRef(ret)
+}
+func x509_CFArrayGetValueAtIndex_trampoline()
+
+//go:linkname x509_CFEqual x509_CFEqual
+//go:cgo_import_dynamic x509_CFEqual CFEqual "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFEqual(a, b CFRef) bool {
+ ret := syscall(funcPC(x509_CFEqual_trampoline), uintptr(a), uintptr(b), 0, 0, 0, 0)
+ return ret == 1
+}
+func x509_CFEqual_trampoline()
+
+//go:linkname x509_CFRelease x509_CFRelease
+//go:cgo_import_dynamic x509_CFRelease CFRelease "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFRelease(ref CFRef) {
+ syscall(funcPC(x509_CFRelease_trampoline), uintptr(ref), 0, 0, 0, 0, 0)
+}
+func x509_CFRelease_trampoline()
+
+// syscall is implemented in the runtime package (runtime/sys_darwin.go)
+func syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) uintptr
+
+// funcPC returns the entry point for f. See comments in runtime/proc.go
+// for the function of the same name.
+//go:nosplit
+func funcPC(f func()) uintptr {
+ return **(**uintptr)(unsafe.Pointer(&f))
+}
diff --git a/src/crypto/x509/internal/macOS/corefoundation.s b/src/crypto/x509/internal/macOS/corefoundation.s
new file mode 100644
index 0000000000..8f6be47e4b
--- /dev/null
+++ b/src/crypto/x509/internal/macOS/corefoundation.s
@@ -0,0 +1,26 @@
+// Copyright 2020 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,amd64
+
+#include "textflag.h"
+
+TEXT ·x509_CFArrayGetCount_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayGetCount(SB)
+TEXT ·x509_CFArrayGetValueAtIndex_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayGetValueAtIndex(SB)
+TEXT ·x509_CFDataGetBytePtr_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDataGetBytePtr(SB)
+TEXT ·x509_CFDataGetLength_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDataGetLength(SB)
+TEXT ·x509_CFStringCreateWithBytes_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFStringCreateWithBytes(SB)
+TEXT ·x509_CFRelease_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFRelease(SB)
+TEXT ·x509_CFDictionaryGetValueIfPresent_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDictionaryGetValueIfPresent(SB)
+TEXT ·x509_CFNumberGetValue_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFNumberGetValue(SB)
+TEXT ·x509_CFEqual_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFEqual(SB)
diff --git a/src/crypto/x509/internal/macOS/security.go b/src/crypto/x509/internal/macOS/security.go
new file mode 100644
index 0000000000..64fe206390
--- /dev/null
+++ b/src/crypto/x509/internal/macOS/security.go
@@ -0,0 +1,116 @@
+// Copyright 2020 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,amd64
+
+package macOS
+
+import (
+ "errors"
+ "strconv"
+ "unsafe"
+)
+
+// Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h
+
+type SecTrustSettingsResult int32
+
+const (
+ SecTrustSettingsResultInvalid SecTrustSettingsResult = iota
+ SecTrustSettingsResultTrustRoot
+ SecTrustSettingsResultTrustAsRoot
+ SecTrustSettingsResultDeny
+ SecTrustSettingsResultUnspecified
+)
+
+type SecTrustSettingsDomain int32
+
+const (
+ SecTrustSettingsDomainUser SecTrustSettingsDomain = iota
+ SecTrustSettingsDomainAdmin
+ SecTrustSettingsDomainSystem
+)
+
+type OSStatus struct {
+ call string
+ status int32
+}
+
+func (s OSStatus) Error() string {
+ return s.call + " error: " + strconv.Itoa(int(s.status))
+}
+
+// Dictionary keys are defined as build-time strings with CFSTR, but the Go
+// linker's internal linking mode can't handle CFSTR relocations. Create our
+// own dynamic strings instead and just never release them.
+//
+// Note that this might be the only thing that can break over time if
+// these values change, as the ABI arguably requires using the strings
+// pointed to by the symbols, not values that happen to be equal to them.
+
+var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult")
+var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy")
+var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString")
+var SecPolicyOid = StringToCFString("SecPolicyOid")
+var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO
+
+var ErrNoTrustSettings = errors.New("no trust settings found")
+
+const errSecNoTrustSettings = -25263
+
+//go:linkname x509_SecTrustSettingsCopyCertificates x509_SecTrustSettingsCopyCertificates
+//go:cgo_import_dynamic x509_SecTrustSettingsCopyCertificates SecTrustSettingsCopyCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) {
+ ret := syscall(funcPC(x509_SecTrustSettingsCopyCertificates_trampoline), uintptr(domain),
+ uintptr(unsafe.Pointer(&certArray)), 0, 0, 0, 0)
+ if int32(ret) == errSecNoTrustSettings {
+ return 0, ErrNoTrustSettings
+ } else if ret != 0 {
+ return 0, OSStatus{"SecTrustSettingsCopyCertificates", int32(ret)}
+ }
+ return certArray, nil
+}
+func x509_SecTrustSettingsCopyCertificates_trampoline()
+
+const kSecFormatX509Cert int32 = 9
+
+//go:linkname x509_SecItemExport x509_SecItemExport
+//go:cgo_import_dynamic x509_SecItemExport SecItemExport "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecItemExport(cert CFRef) (data CFRef, err error) {
+ ret := syscall(funcPC(x509_SecItemExport_trampoline), uintptr(cert), uintptr(kSecFormatX509Cert),
+ 0 /* flags */, 0 /* keyParams */, uintptr(unsafe.Pointer(&data)), 0)
+ if ret != 0 {
+ return 0, OSStatus{"SecItemExport", int32(ret)}
+ }
+ return data, nil
+}
+func x509_SecItemExport_trampoline()
+
+const errSecItemNotFound = -25300
+
+//go:linkname x509_SecTrustSettingsCopyTrustSettings x509_SecTrustSettingsCopyTrustSettings
+//go:cgo_import_dynamic x509_SecTrustSettingsCopyTrustSettings SecTrustSettingsCopyTrustSettings "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) {
+ ret := syscall(funcPC(x509_SecTrustSettingsCopyTrustSettings_trampoline), uintptr(cert), uintptr(domain),
+ uintptr(unsafe.Pointer(&trustSettings)), 0, 0, 0)
+ if int32(ret) == errSecItemNotFound {
+ return 0, ErrNoTrustSettings
+ } else if ret != 0 {
+ return 0, OSStatus{"SecTrustSettingsCopyTrustSettings", int32(ret)}
+ }
+ return trustSettings, nil
+}
+func x509_SecTrustSettingsCopyTrustSettings_trampoline()
+
+//go:linkname x509_SecPolicyCopyProperties x509_SecPolicyCopyProperties
+//go:cgo_import_dynamic x509_SecPolicyCopyProperties SecPolicyCopyProperties "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecPolicyCopyProperties(policy CFRef) CFRef {
+ ret := syscall(funcPC(x509_SecPolicyCopyProperties_trampoline), uintptr(policy), 0, 0, 0, 0, 0)
+ return CFRef(ret)
+}
+func x509_SecPolicyCopyProperties_trampoline()
diff --git a/src/crypto/x509/internal/macOS/security.s b/src/crypto/x509/internal/macOS/security.s
new file mode 100644
index 0000000000..1630c55bab
--- /dev/null
+++ b/src/crypto/x509/internal/macOS/security.s
@@ -0,0 +1,16 @@
+// Copyright 2020 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,amd64
+
+#include "textflag.h"
+
+TEXT ·x509_SecTrustSettingsCopyCertificates_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustSettingsCopyCertificates(SB)
+TEXT ·x509_SecItemExport_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecItemExport(SB)
+TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustSettingsCopyTrustSettings(SB)
+TEXT ·x509_SecPolicyCopyProperties_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecPolicyCopyProperties(SB)
diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go
index 240296247d..da5e91b91c 100644
--- a/src/crypto/x509/root.go
+++ b/src/crypto/x509/root.go
@@ -4,6 +4,8 @@
package x509
+//go:generate go run root_darwin_ios_gen.go -version 55161.80.1
+
import "sync"
var (
diff --git a/src/crypto/x509/root_cgo_darwin.go b/src/crypto/x509/root_cgo_darwin_amd64.go
index 784470bb3b..15c72cc0c8 100644
--- a/src/crypto/x509/root_cgo_darwin.go
+++ b/src/crypto/x509/root_cgo_darwin_amd64.go
@@ -2,10 +2,14 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build cgo,!arm64,!ios
+// +build !ios
package x509
+// This cgo implementation exists only to support side-by-side testing by
+// TestSystemRoots. It can be removed once we are confident in the no-cgo
+// implementation.
+
/*
#cgo CFLAGS: -mmacosx-version-min=10.11
#cgo LDFLAGS: -framework CoreFoundation -framework Security
@@ -283,7 +287,11 @@ import (
"unsafe"
)
-func loadSystemRoots() (*CertPool, error) {
+func init() {
+ loadSystemRootsWithCgo = _loadSystemRootsWithCgo
+}
+
+func _loadSystemRootsWithCgo() (*CertPool, error) {
var data, untrustedData C.CFDataRef
err := C.CopyPEMRoots(&data, &untrustedData, C.bool(debugDarwinRoots))
if err == -1 {
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
deleted file mode 100644
index 2f6a8b8d60..0000000000
--- a/src/crypto/x509/root_darwin.go
+++ /dev/null
@@ -1,288 +0,0 @@
-// Copyright 2013 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.
-
-//go:generate go run root_darwin_arm_gen.go -output root_darwin_armx.go
-
-package x509
-
-import (
- "bufio"
- "bytes"
- "crypto/sha1"
- "encoding/pem"
- "fmt"
- "io"
- "io/ioutil"
- "os"
- "os/exec"
- "path/filepath"
- "strings"
- "sync"
-)
-
-var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
-
-func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
- return nil, nil
-}
-
-// This code is only used when compiling without cgo.
-// It is here, instead of root_nocgo_darwin.go, so that tests can check it
-// even if the tests are run with cgo enabled.
-// The linker will not include these unused functions in binaries built with cgo enabled.
-
-// execSecurityRoots finds the macOS list of trusted root certificates
-// using only command-line tools. This is our fallback path when cgo isn't available.
-//
-// The strategy is as follows:
-//
-// 1. Run "security trust-settings-export" and "security
-// trust-settings-export -d" to discover the set of certs with some
-// user-tweaked trust policy. We're too lazy to parse the XML
-// (Issue 26830) to understand what the trust
-// policy actually is. We just learn that there is _some_ policy.
-//
-// 2. Run "security find-certificate" to dump the list of system root
-// CAs in PEM format.
-//
-// 3. For each dumped cert, conditionally verify it with "security
-// verify-cert" if that cert was in the set discovered in Step 1.
-// Without the Step 1 optimization, running "security verify-cert"
-// 150-200 times takes 3.5 seconds. With the optimization, the
-// whole process takes about 180 milliseconds with 1 untrusted root
-// CA. (Compared to 110ms in the cgo path)
-func execSecurityRoots() (*CertPool, error) {
- hasPolicy, err := getCertsWithTrustPolicy()
- if err != nil {
- return nil, err
- }
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: %d certs have a trust policy\n", len(hasPolicy))
- }
-
- keychains := []string{"/Library/Keychains/System.keychain"}
-
- // Note that this results in trusting roots from $HOME/... (the environment
- // variable), which might not be expected.
- home, err := os.UserHomeDir()
- if err != nil {
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: can't get user home directory: %v\n", err)
- }
- } else {
- keychains = append(keychains,
- filepath.Join(home, "/Library/Keychains/login.keychain"),
-
- // Fresh installs of Sierra use a slightly different path for the login keychain
- filepath.Join(home, "/Library/Keychains/login.keychain-db"),
- )
- }
-
- type rootCandidate struct {
- c *Certificate
- system bool
- }
-
- var (
- mu sync.Mutex
- roots = NewCertPool()
- numVerified int // number of execs of 'security verify-cert', for debug stats
- wg sync.WaitGroup
- verifyCh = make(chan rootCandidate)
- )
-
- // Using 4 goroutines to pipe into verify-cert seems to be
- // about the best we can do. The verify-cert binary seems to
- // just RPC to another server with coarse locking anyway, so
- // running 16 at a time for instance doesn't help at all. Due
- // to the "if hasPolicy" check below, though, we will rarely
- // (or never) call verify-cert on stock macOS systems, though.
- // The hope is that we only call verify-cert when the user has
- // tweaked their trust policy. These 4 goroutines are only
- // defensive in the pathological case of many trust edits.
- for i := 0; i < 4; i++ {
- wg.Add(1)
- go func() {
- defer wg.Done()
- for cert := range verifyCh {
- sha1CapHex := fmt.Sprintf("%X", sha1.Sum(cert.c.Raw))
-
- var valid bool
- verifyChecks := 0
- if hasPolicy[sha1CapHex] {
- verifyChecks++
- valid = verifyCertWithSystem(cert.c)
- } else {
- // Certificates not in SystemRootCertificates without user
- // or admin trust settings are not trusted.
- valid = cert.system
- }
-
- mu.Lock()
- numVerified += verifyChecks
- if valid {
- roots.AddCert(cert.c)
- }
- mu.Unlock()
- }
- }()
- }
- err = forEachCertInKeychains(keychains, func(cert *Certificate) {
- verifyCh <- rootCandidate{c: cert, system: false}
- })
- if err != nil {
- close(verifyCh)
- return nil, err
- }
- err = forEachCertInKeychains([]string{
- "/System/Library/Keychains/SystemRootCertificates.keychain",
- }, func(cert *Certificate) {
- verifyCh <- rootCandidate{c: cert, system: true}
- })
- if err != nil {
- close(verifyCh)
- return nil, err
- }
- close(verifyCh)
- wg.Wait()
-
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: ran security verify-cert %d times\n", numVerified)
- }
-
- return roots, nil
-}
-
-func forEachCertInKeychains(paths []string, f func(*Certificate)) error {
- args := append([]string{"find-certificate", "-a", "-p"}, paths...)
- cmd := exec.Command("/usr/bin/security", args...)
- data, err := cmd.Output()
- if err != nil {
- return err
- }
- for len(data) > 0 {
- var block *pem.Block
- block, data = pem.Decode(data)
- if block == nil {
- break
- }
- if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
- continue
- }
- cert, err := ParseCertificate(block.Bytes)
- if err != nil {
- continue
- }
- f(cert)
- }
- return nil
-}
-
-func verifyCertWithSystem(cert *Certificate) bool {
- data := pem.EncodeToMemory(&pem.Block{
- Type: "CERTIFICATE", Bytes: cert.Raw,
- })
-
- f, err := ioutil.TempFile("", "cert")
- if err != nil {
- fmt.Fprintf(os.Stderr, "can't create temporary file for cert: %v", err)
- return false
- }
- defer os.Remove(f.Name())
- if _, err := f.Write(data); err != nil {
- fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
- return false
- }
- if err := f.Close(); err != nil {
- fmt.Fprintf(os.Stderr, "can't write temporary file for cert: %v", err)
- return false
- }
- cmd := exec.Command("/usr/bin/security", "verify-cert", "-p", "ssl", "-c", f.Name(), "-l", "-L")
- var stderr bytes.Buffer
- if debugDarwinRoots {
- cmd.Stderr = &stderr
- }
- if err := cmd.Run(); err != nil {
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: verify-cert rejected %s: %q\n", cert.Subject, bytes.TrimSpace(stderr.Bytes()))
- }
- return false
- }
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: verify-cert approved %s\n", cert.Subject)
- }
- return true
-}
-
-// getCertsWithTrustPolicy returns the set of certs that have a
-// possibly-altered trust policy. The keys of the map are capitalized
-// sha1 hex of the raw cert.
-// They are the certs that should be checked against `security
-// verify-cert` to see whether the user altered the default trust
-// settings. This code is only used for cgo-disabled builds.
-func getCertsWithTrustPolicy() (map[string]bool, error) {
- set := map[string]bool{}
- td, err := ioutil.TempDir("", "x509trustpolicy")
- if err != nil {
- return nil, err
- }
- defer os.RemoveAll(td)
- run := func(file string, args ...string) error {
- file = filepath.Join(td, file)
- args = append(args, file)
- cmd := exec.Command("/usr/bin/security", args...)
- var stderr bytes.Buffer
- cmd.Stderr = &stderr
- if err := cmd.Run(); err != nil {
- // If there are no trust settings, the
- // `security trust-settings-export` command
- // fails with:
- // exit status 1, SecTrustSettingsCreateExternalRepresentation: No Trust Settings were found.
- // Rather than match on English substrings that are probably
- // localized on macOS, just interpret any failure to mean that
- // there are no trust settings.
- if debugDarwinRoots {
- fmt.Fprintf(os.Stderr, "crypto/x509: exec %q: %v, %s\n", cmd.Args, err, stderr.Bytes())
- }
- return nil
- }
-
- f, err := os.Open(file)
- if err != nil {
- return err
- }
- defer f.Close()
-
- // Gather all the runs of 40 capitalized hex characters.
- br := bufio.NewReader(f)
- var hexBuf bytes.Buffer
- for {
- b, err := br.ReadByte()
- isHex := ('A' <= b && b <= 'F') || ('0' <= b && b <= '9')
- if isHex {
- hexBuf.WriteByte(b)
- } else {
- if hexBuf.Len() == 40 {
- set[hexBuf.String()] = true
- }
- hexBuf.Reset()
- }
- if err == io.EOF {
- break
- }
- if err != nil {
- return err
- }
- }
-
- return nil
- }
- if err := run("user", "trust-settings-export"); err != nil {
- return nil, fmt.Errorf("dump-trust-settings (user): %v", err)
- }
- if err := run("admin", "trust-settings-export", "-d"); err != nil {
- return nil, fmt.Errorf("dump-trust-settings (admin): %v", err)
- }
- return set, nil
-}
diff --git a/src/crypto/x509/root_darwin_amd64.go b/src/crypto/x509/root_darwin_amd64.go
new file mode 100644
index 0000000000..ccc37b8ec5
--- /dev/null
+++ b/src/crypto/x509/root_darwin_amd64.go
@@ -0,0 +1,243 @@
+// Copyright 2020 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 !ios
+
+package x509
+
+import (
+ "bytes"
+ "crypto/x509/internal/macOS"
+ "fmt"
+ "os"
+ "strings"
+)
+
+var debugDarwinRoots = strings.Contains(os.Getenv("GODEBUG"), "x509roots=1")
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+// loadSystemRootsWithCgo is set in root_cgo_darwin_amd64.go when cgo is
+// available, and is only used for testing.
+var loadSystemRootsWithCgo func() (*CertPool, error)
+
+func loadSystemRoots() (*CertPool, error) {
+ var trustedRoots []*Certificate
+ untrustedRoots := make(map[string]bool)
+
+ // macOS has three trust domains: one for CAs added by users to their
+ // "login" keychain, one for CAs added by Admins to the "System" keychain,
+ // and one for the CAs that ship with the OS.
+ for _, domain := range []macOS.SecTrustSettingsDomain{
+ macOS.SecTrustSettingsDomainUser,
+ macOS.SecTrustSettingsDomainAdmin,
+ macOS.SecTrustSettingsDomainSystem,
+ } {
+ certs, err := macOS.SecTrustSettingsCopyCertificates(domain)
+ if err == macOS.ErrNoTrustSettings {
+ continue
+ } else if err != nil {
+ return nil, err
+ }
+ defer macOS.CFRelease(certs)
+
+ for i := 0; i < macOS.CFArrayGetCount(certs); i++ {
+ c := macOS.CFArrayGetValueAtIndex(certs, i)
+ cert, err := exportCertificate(c)
+ if err != nil {
+ if debugDarwinRoots {
+ fmt.Fprintf(os.Stderr, "crypto/x509: domain %d, certificate #%d: %v\n", domain, i, err)
+ }
+ continue
+ }
+
+ var result macOS.SecTrustSettingsResult
+ if domain == macOS.SecTrustSettingsDomainSystem {
+ // Certs found in the system domain are always trusted. If the user
+ // configures "Never Trust" on such a cert, it will also be found in the
+ // admin or user domain, causing it to be added to untrustedRoots.
+ result = macOS.SecTrustSettingsResultTrustRoot
+ } else {
+ result, err = sslTrustSettingsResult(c)
+ if err != nil {
+ if debugDarwinRoots {
+ fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %v\n", cert.Subject, err)
+ }
+ continue
+ }
+ if debugDarwinRoots {
+ fmt.Fprintf(os.Stderr, "crypto/x509: trust settings for %v: %d\n", cert.Subject, result)
+ }
+ }
+
+ switch result {
+ // "Note the distinction between the results kSecTrustSettingsResultTrustRoot
+ // and kSecTrustSettingsResultTrustAsRoot: The former can only be applied to
+ // root (self-signed) certificates; the latter can only be applied to
+ // non-root certificates."
+ case macOS.SecTrustSettingsResultTrustRoot:
+ if isRootCertificate(cert) {
+ trustedRoots = append(trustedRoots, cert)
+ }
+ case macOS.SecTrustSettingsResultTrustAsRoot:
+ if !isRootCertificate(cert) {
+ trustedRoots = append(trustedRoots, cert)
+ }
+
+ case macOS.SecTrustSettingsResultDeny:
+ // Add this certificate to untrustedRoots, which are subtracted
+ // from trustedRoots, so that we don't have to evaluate policies
+ // for every root in the system domain, but still apply user and
+ // admin policies that override system roots.
+ untrustedRoots[string(cert.Raw)] = true
+
+ case macOS.SecTrustSettingsResultUnspecified:
+ // Certificates with unspecified trust should be added to a pool
+ // of intermediates for chain building, but we don't support it
+ // at the moment. This is Issue 35631.
+
+ default:
+ if debugDarwinRoots {
+ fmt.Fprintf(os.Stderr, "crypto/x509: unknown trust setting for %v: %d\n", cert.Subject, result)
+ }
+ }
+ }
+ }
+
+ pool := NewCertPool()
+ for _, cert := range trustedRoots {
+ if !untrustedRoots[string(cert.Raw)] {
+ pool.AddCert(cert)
+ }
+ }
+ return pool, nil
+}
+
+// exportCertificate returns a *Certificate for a SecCertificateRef.
+func exportCertificate(cert macOS.CFRef) (*Certificate, error) {
+ data, err := macOS.SecItemExport(cert)
+ if err != nil {
+ return nil, err
+ }
+ defer macOS.CFRelease(data)
+ der := macOS.CFDataToSlice(data)
+
+ return ParseCertificate(der)
+}
+
+// isRootCertificate reports whether Subject and Issuer match.
+func isRootCertificate(cert *Certificate) bool {
+ return bytes.Equal(cert.RawSubject, cert.RawIssuer)
+}
+
+// sslTrustSettingsResult obtains the final kSecTrustSettingsResult value for a
+// certificate in the user or admin domain, combining usage constraints for the
+// SSL SecTrustSettingsPolicy,
+//
+// It ignores SecTrustSettingsKeyUsage and kSecTrustSettingsAllowedError, and
+// doesn't support kSecTrustSettingsDefaultRootCertSetting.
+//
+// https://developer.apple.com/documentation/security/1400261-sectrustsettingscopytrustsetting
+func sslTrustSettingsResult(cert macOS.CFRef) (macOS.SecTrustSettingsResult, error) {
+ // In Apple's implementation user trust settings override admin trust settings
+ // (which themselves override system trust settings). If SecTrustSettingsCopyTrustSettings
+ // fails, or returns a NULL trust settings, when looking for the user trust
+ // settings then fallback to checking the admin trust settings.
+ //
+ // See Security-59306.41.2/trust/headers/SecTrustSettings.h for a description of
+ // the trust settings overrides, and SecLegacyAnchorSourceCopyUsageConstraints in
+ // Security-59306.41.2/trust/trustd/SecCertificateSource.c for a concrete example
+ // of how Apple applies the override in the case of NULL trust settings, or non
+ // success errors.
+ trustSettings, err := macOS.SecTrustSettingsCopyTrustSettings(cert, macOS.SecTrustSettingsDomainUser)
+ if err != nil || trustSettings == 0 {
+ if debugDarwinRoots && err != macOS.ErrNoTrustSettings {
+ fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainUser failed: %s\n", err)
+ }
+ trustSettings, err = macOS.SecTrustSettingsCopyTrustSettings(cert, macOS.SecTrustSettingsDomainAdmin)
+ }
+ if err != nil || trustSettings == 0 {
+ // If there are neither user nor admin trust settings for a certificate returned
+ // from SecTrustSettingsCopyCertificates Apple returns kSecTrustSettingsResultInvalid,
+ // as this method is intended to return certificates _which have trust settings_.
+ // The most likely case for this being triggered is that the existing trust settings
+ // are invalid and cannot be properly parsed. In this case SecTrustSettingsCopyTrustSettings
+ // returns errSecInvalidTrustSettings. The existing cgo implementation returns
+ // kSecTrustSettingsResultUnspecified in this case, which mostly matches the Apple
+ // implementation because we don't do anything with certificates marked with this
+ // result.
+ //
+ // See SecPVCGetTrustSettingsResult in Security-59306.41.2/trust/trustd/SecPolicyServer.c
+ if debugDarwinRoots && err != macOS.ErrNoTrustSettings {
+ fmt.Fprintf(os.Stderr, "crypto/x509: SecTrustSettingsCopyTrustSettings for SecTrustSettingsDomainAdmin failed: %s\n", err)
+ }
+ return macOS.SecTrustSettingsResultUnspecified, nil
+ }
+ defer macOS.CFRelease(trustSettings)
+
+ // "An empty trust settings array means 'always trust this certificate' with an
+ // overall trust setting for the certificate of kSecTrustSettingsResultTrustRoot."
+ if macOS.CFArrayGetCount(trustSettings) == 0 {
+ return macOS.SecTrustSettingsResultTrustRoot, nil
+ }
+
+ isSSLPolicy := func(policyRef macOS.CFRef) bool {
+ properties := macOS.SecPolicyCopyProperties(policyRef)
+ defer macOS.CFRelease(properties)
+ if v, ok := macOS.CFDictionaryGetValueIfPresent(properties, macOS.SecPolicyOid); ok {
+ return macOS.CFEqual(v, macOS.CFRef(macOS.SecPolicyAppleSSL))
+ }
+ return false
+ }
+
+ for i := 0; i < macOS.CFArrayGetCount(trustSettings); i++ {
+ tSetting := macOS.CFArrayGetValueAtIndex(trustSettings, i)
+
+ // First, check if this trust setting is constrained to a non-SSL policy.
+ if policyRef, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsPolicy); ok {
+ if !isSSLPolicy(policyRef) {
+ continue
+ }
+ }
+
+ // Then check if it is restricted to a hostname, so not a root.
+ if _, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsPolicyString); ok {
+ continue
+ }
+
+ cfNum, ok := macOS.CFDictionaryGetValueIfPresent(tSetting, macOS.SecTrustSettingsResultKey)
+ // "If this key is not present, a default value of kSecTrustSettingsResultTrustRoot is assumed."
+ if !ok {
+ return macOS.SecTrustSettingsResultTrustRoot, nil
+ }
+ result, err := macOS.CFNumberGetValue(cfNum)
+ if err != nil {
+ return 0, err
+ }
+
+ // If multiple dictionaries match, we are supposed to "OR" them,
+ // the semantics of which are not clear. Since TrustRoot and TrustAsRoot
+ // are mutually exclusive, Deny should probably override, and Invalid and
+ // Unspecified be overridden, approximate this by stopping at the first
+ // TrustRoot, TrustAsRoot or Deny.
+ switch r := macOS.SecTrustSettingsResult(result); r {
+ case macOS.SecTrustSettingsResultTrustRoot,
+ macOS.SecTrustSettingsResultTrustAsRoot,
+ macOS.SecTrustSettingsResultDeny:
+ return r, nil
+ }
+ }
+
+ // If trust settings are present, but none of them match the policy...
+ // the docs don't tell us what to do.
+ //
+ // "Trust settings for a given use apply if any of the dictionaries in the
+ // certificate’s trust settings array satisfies the specified use." suggests
+ // that it's as if there were no trust settings at all, so we should maybe
+ // fallback to the admin trust settings? TODO(golang.org/issue/38888).
+
+ return macOS.SecTrustSettingsResultUnspecified, nil
+}
diff --git a/src/crypto/x509/root_darwin_arm_gen.go b/src/crypto/x509/root_darwin_arm_gen.go
deleted file mode 100644
index cba950fcc9..0000000000
--- a/src/crypto/x509/root_darwin_arm_gen.go
+++ /dev/null
@@ -1,184 +0,0 @@
-// 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 ignore
-
-// Generates root_darwin_arm64.go.
-//
-// As of iOS 8, there is no API for querying the system trusted X.509 root
-// certificates. We could use SecTrustEvaluate to verify that a trust chain
-// exists for a certificate, but the x509 API requires returning the entire
-// chain.
-//
-// Apple publishes the list of trusted root certificates for iOS on
-// support.apple.com. So we parse the list and extract the certificates from
-// an OS X machine and embed them into the x509 package.
-package main
-
-import (
- "bytes"
- "crypto/sha256"
- "crypto/x509"
- "encoding/hex"
- "encoding/pem"
- "flag"
- "fmt"
- "go/format"
- "io/ioutil"
- "log"
- "net/http"
- "os/exec"
- "regexp"
- "strings"
-)
-
-var output = flag.String("output", "root_darwin_arm64.go", "file name to write")
-
-func main() {
- certs, err := selectCerts()
- if err != nil {
- log.Fatal(err)
- }
-
- buf := new(bytes.Buffer)
-
- fmt.Fprintf(buf, "// Code generated by root_darwin_arm_gen --output %s; DO NOT EDIT.\n", *output)
- fmt.Fprintf(buf, "%s", header)
-
- fmt.Fprintf(buf, "const systemRootsPEM = `\n")
- for _, cert := range certs {
- b := &pem.Block{
- Type: "CERTIFICATE",
- Bytes: cert.Raw,
- }
- if err := pem.Encode(buf, b); err != nil {
- log.Fatal(err)
- }
- }
- fmt.Fprintf(buf, "`")
-
- source, err := format.Source(buf.Bytes())
- if err != nil {
- log.Fatal("source format error:", err)
- }
- if err := ioutil.WriteFile(*output, source, 0644); err != nil {
- log.Fatal(err)
- }
-}
-
-func selectCerts() ([]*x509.Certificate, error) {
- ids, err := fetchCertIDs()
- if err != nil {
- return nil, err
- }
-
- scerts, err := sysCerts()
- if err != nil {
- return nil, err
- }
-
- var certs []*x509.Certificate
- for _, id := range ids {
- if c, ok := scerts[id.fingerprint]; ok {
- certs = append(certs, c)
- } else {
- fmt.Printf("WARNING: cannot find certificate: %s (fingerprint: %s)\n", id.name, id.fingerprint)
- }
- }
- return certs, nil
-}
-
-func sysCerts() (certs map[string]*x509.Certificate, err error) {
- cmd := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p", "/System/Library/Keychains/SystemRootCertificates.keychain")
- data, err := cmd.Output()
- if err != nil {
- return nil, err
- }
- certs = make(map[string]*x509.Certificate)
- for len(data) > 0 {
- var block *pem.Block
- block, data = pem.Decode(data)
- if block == nil {
- break
- }
- if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
- continue
- }
-
- cert, err := x509.ParseCertificate(block.Bytes)
- if err != nil {
- continue
- }
-
- fingerprint := sha256.Sum256(cert.Raw)
- certs[hex.EncodeToString(fingerprint[:])] = cert
- }
- return certs, nil
-}
-
-type certID struct {
- name string
- fingerprint string
-}
-
-// fetchCertIDs fetches IDs of iOS X509 certificates from apple.com.
-func fetchCertIDs() ([]certID, error) {
- // Download the iOS 11 support page. The index for all iOS versions is here:
- // https://support.apple.com/en-us/HT204132
- resp, err := http.Get("https://support.apple.com/en-us/HT208125")
- if err != nil {
- return nil, err
- }
- defer resp.Body.Close()
- body, err := ioutil.ReadAll(resp.Body)
- if err != nil {
- return nil, err
- }
- text := string(body)
- text = text[strings.Index(text, "<div id=trusted"):]
- text = text[:strings.Index(text, "</div>")]
-
- var ids []certID
- cols := make(map[string]int)
- for i, rowmatch := range regexp.MustCompile("(?s)<tr>(.*?)</tr>").FindAllStringSubmatch(text, -1) {
- row := rowmatch[1]
- if i == 0 {
- // Parse table header row to extract column names
- for i, match := range regexp.MustCompile("(?s)<th>(.*?)</th>").FindAllStringSubmatch(row, -1) {
- cols[match[1]] = i
- }
- continue
- }
-
- values := regexp.MustCompile("(?s)<td>(.*?)</td>").FindAllStringSubmatch(row, -1)
- name := values[cols["Certificate name"]][1]
- fingerprint := values[cols["Fingerprint (SHA-256)"]][1]
- fingerprint = strings.ReplaceAll(fingerprint, "<br>", "")
- fingerprint = strings.ReplaceAll(fingerprint, "\n", "")
- fingerprint = strings.ReplaceAll(fingerprint, " ", "")
- fingerprint = strings.ToLower(fingerprint)
-
- ids = append(ids, certID{
- name: name,
- fingerprint: fingerprint,
- })
- }
- return ids, nil
-}
-
-const header = `
-// 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 !x509omitbundledroots
-
-package x509
-
-func loadSystemRoots() (*CertPool, error) {
- p := NewCertPool()
- p.AppendCertsFromPEM([]byte(systemRootsPEM))
- return p, nil
-}
-`
diff --git a/src/crypto/x509/root_darwin_arm64.go b/src/crypto/x509/root_darwin_ios.go
index 639c6ae7de..5ecc4911b3 100644
--- a/src/crypto/x509/root_darwin_arm64.go
+++ b/src/crypto/x509/root_darwin_ios.go
@@ -1,13 +1,18 @@
-// Code generated by root_darwin_arm_gen --output root_darwin_arm64.go; DO NOT EDIT.
-
-// 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.
+// Code generated by root_darwin_ios_gen.go -version 55161.80.1; DO NOT EDIT.
+// Update the version in root.go and regenerate with "go generate".
+// +build darwin,arm64 darwin,amd64,ios
// +build !x509omitbundledroots
package x509
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+// loadSystemRootsWithCgo is not available on iOS.
+var loadSystemRootsWithCgo func() (*CertPool, error)
+
func loadSystemRoots() (*CertPool, error) {
p := NewCertPool()
p.AppendCertsFromPEM([]byte(systemRootsPEM))
@@ -15,6 +20,9 @@ func loadSystemRoots() (*CertPool, error) {
}
const systemRootsPEM = `
+# "AAA Certificate Services"
+# D7 A7 A0 FB 5D 7E 27 31 D7 71 E9 48 4E BC DE F7
+# 1D 5F 0C 3E 0A 29 48 78 2B C8 3E E0 EA 69 9E F4
-----BEGIN CERTIFICATE-----
MIIEMjCCAxqgAwIBAgIBATANBgkqhkiG9w0BAQUFADB7MQswCQYDVQQGEwJHQjEb
MBkGA1UECAwSR3JlYXRlciBNYW5jaGVzdGVyMRAwDgYDVQQHDAdTYWxmb3JkMRow
@@ -40,6 +48,44 @@ G9w84FoVxp7Z8VlIMCFlA2zs6SFz7JsDoeA3raAVGI/6ugLOpyypEBMs1OUIJqsi
l2D4kF501KKaU73yqWjgom7C12yxow+ev+to51byrvLjKzg6CYG1a4XXvi3tPxq3
smPi9WIsgtRqAEFQ8TmDn5XpNpaYbg==
-----END CERTIFICATE-----
+# "AC RAIZ FNMT-RCM"
+# EB C5 57 0C 29 01 8C 4D 67 B1 AA 12 7B AF 12 F7
+# 03 B4 61 1E BC 17 B7 DA B5 57 38 94 17 9B 93 FA
+-----BEGIN CERTIFICATE-----
+MIIFgzCCA2ugAwIBAgIPXZONMGc2yAYdGsdUhGkHMA0GCSqGSIb3DQEBCwUAMDsx
+CzAJBgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJ
+WiBGTk1ULVJDTTAeFw0wODEwMjkxNTU5NTZaFw0zMDAxMDEwMDAwMDBaMDsxCzAJ
+BgNVBAYTAkVTMREwDwYDVQQKDAhGTk1ULVJDTTEZMBcGA1UECwwQQUMgUkFJWiBG
+Tk1ULVJDTTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALpxgHpMhm5/
+yBNtwMZ9HACXjywMI7sQmkCpGreHiPibVmr75nuOi5KOpyVdWRHbNi63URcfqQgf
+BBckWKo3Shjf5TnUV/3XwSyRAZHiItQDwFj8d0fsjz50Q7qsNI1NOHZnjrDIbzAz
+WHFctPVrbtQBULgTfmxKo0nRIBnuvMApGGWn3v7v3QqQIecaZ5JCEJhfTzC8PhxF
+tBDXaEAUwED653cXeuYLj2VbPNmaUtu1vZ5Gzz3rkQUCwJaydkxNEJY7kvqcfw+Z
+374jNUUeAlz+taibmSXaXvMiwzn15Cou08YfxGyqxRxqAQVKL9LFwag0Jl1mpdIC
+IfkYtwb1TplvqKtMUejPUBjFd8g5CSxJkjKZqLsXF3mwWsXmo8RZZUc1g16p6DUL
+mbvkzSDGm0oGObVo/CK67lWMK07q87Hj/LaZmtVC+nFNCM+HHmpxffnTtOmlcYF7
+wk5HlqX2doWjKI/pgG6BU6VtX7hI+cL5NqYuSf+4lsKMB7ObiFj86xsc3i1w4peS
+MKGJ47xVqCfWS+2QrYv6YyVZLag13cqXM7zlzced0ezvXg5KkAYmY6252TUtB7p2
+ZSysV4999AeU14ECll2jB0nVetBX+RvnU0Z1qrB5QstocQjpYL05ac70r8NWQMet
+UqIJ5G+GR4of6ygnXYMgrwTJbFaai0b1AgMBAAGjgYMwgYAwDwYDVR0TAQH/BAUw
+AwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFPd9xf3E6Jobd2Sn9R2gzL+H
+YJptMD4GA1UdIAQ3MDUwMwYEVR0gADArMCkGCCsGAQUFBwIBFh1odHRwOi8vd3d3
+LmNlcnQuZm5tdC5lcy9kcGNzLzANBgkqhkiG9w0BAQsFAAOCAgEAB5BK3/MjTvDD
+nFFlm5wioooMhfNzKWtN/gHiqQxjAb8EZ6WdmF/9ARP67Jpi6Yb+tmLSbkyU+8B1
+RXxlDPiyN8+sD8+Nb/kZ94/sHvJwnvDKuO+3/3Y3dlv2bojzr2IyIpMNOmqOFGYM
+LVN0V2Ue1bLdI4E7pWYjJ2cJj+F3qkPNZVEI7VFY/uY5+ctHhKQV8Xa7pO6kO8Rf
+77IzlhEYt8llvhjho6Tc+hj507wTmzl6NLrTQfv6MooqtyuGC2mDOL7Nii4LcK2N
+JpLuHvUBKwrZ1pebbuCoGRw6IYsMHkCtA+fdZn71uSANA+iW+YJF1DngoABd15jm
+fZ5nc8OaKveri6E6FO80vFIOiZiaBECEHX5FaZNXzuvO+FB8TxxuBEOb+dY7Ixjp
+6o7RTUaN8Tvkasq6+yO3m/qZASlaWFot4/nUbQ4mrcFuNLwy+AwF+mWj2zs3gyLp
+1txyM/1d8iC9djwj2ij3+RvrWWTV3F9yfiD8zYm1kGdNYno/Tq0dwzn+evQoFt9B
+9kiABdcPUXmsEKvU7ANm5mqwujGSQkBqvjrTcuFqN1W8rB2Vt2lh8kORdOag0wok
+RqEIr9baRRmW1FMdW4R58MD3R++Lj8UGrp1MYp3/RgT408m2ECVAdf4WqslKYIYv
+uu8wd+RU4riEmViAqhOLUTpPSPaLtrM=
+-----END CERTIFICATE-----
+# "Actalis Authentication Root CA"
+# 55 92 60 84 EC 96 3A 64 B9 6E 2A BE 01 CE 0B A8
+# 6A 64 FB FE BC C7 AA B5 AF C1 55 B3 7F D7 60 66
-----BEGIN CERTIFICATE-----
MIIFuzCCA6OgAwIBAgIIVwoRl0LE48wwDQYJKoZIhvcNAQELBQAwazELMAkGA1UE
BhMCSVQxDjAMBgNVBAcMBU1pbGFuMSMwIQYDVQQKDBpBY3RhbGlzIFMucC5BLi8w
@@ -73,6 +119,9 @@ ZCzJJ7VLkn5l/9Mt4blOvH+kQSGQQXemOR/qnuOf0GZvBeyqdn6/axag67XH/JJU
LysRJyU3eExRarDzzFhdFPFqSBX/wge2sY0PjlxQRrM9vwGYT7JZVEc+NHt4bVaT
LnPqZih4zR0Uv6CPLy64Lo7yFIrM6bV8+2ydDKXhlg==
-----END CERTIFICATE-----
+# "AddTrust Class 1 CA Root"
+# 8C 72 09 27 9A C0 4E 27 5E 16 D0 7F D3 B7 75 E8
+# 01 54 B5 96 80 46 E3 1F 52 DD 25 76 63 24 E9 A7
-----BEGIN CERTIFICATE-----
MIIEGDCCAwCgAwIBAgIBATANBgkqhkiG9w0BAQUFADBlMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxHTAbBgNVBAsTFEFkZFRydXN0IFRUUCBOZXR3
@@ -97,6 +146,9 @@ eDdXL+gzB2ffHsdrKpV2ro9Xo/D0UrSpUwjP4E/TelOL/bscVjby/rK25Xa71SJl
pz/+0WatC7xrmYbvP33zGDLKe8bjq2RGlfgmadlVg3sslgf/WSxEo8bl6ancoWOA
WiFeIc9TVPC6b4nbqKqVz4vjccweGyBECMB6tkD9xOQ14R0WHNC8K47Wcdk=
-----END CERTIFICATE-----
+# "AddTrust External CA Root"
+# 68 7F A4 51 38 22 78 FF F0 C8 B1 1F 8D 43 D5 76
+# 67 1C 6E B2 BC EA B4 13 FB 83 D9 65 D0 6D 2F F2
-----BEGIN CERTIFICATE-----
MIIENjCCAx6gAwIBAgIBATANBgkqhkiG9w0BAQUFADBvMQswCQYDVQQGEwJTRTEU
MBIGA1UEChMLQWRkVHJ1c3QgQUIxJjAkBgNVBAsTHUFkZFRydXN0IEV4dGVybmFs
@@ -122,6 +174,9 @@ Nr4TDea9Y355e6cJDUCrat2PisP29owaQgVR1EX1n6diIWgVIEM8med8vSTYqZEX
c4g/VhsxOBi0cQ+azcgOno4uG+GMmIPLHzHxREzGBHNJdmAPx/i9F4BrLunMTA5a
mnkPIAou1Z5jJh5VkpTYghdae9C8x49OhgQ=
-----END CERTIFICATE-----
+# "Admin-Root-CA"
+# A3 1F 09 30 53 BD 12 C1 F5 C3 C6 EF D4 98 02 3F
+# D2 91 4D 77 58 D0 5D 69 8C E0 84 B5 06 26 E0 E5
-----BEGIN CERTIFICATE-----
MIIFVTCCBD2gAwIBAgIEO/OB0DANBgkqhkiG9w0BAQUFADBsMQswCQYDVQQGEwJj
aDEOMAwGA1UEChMFYWRtaW4xETAPBgNVBAsTCFNlcnZpY2VzMSIwIAYDVQQLExlD
@@ -153,6 +208,9 @@ a440xTk59pSYux8OHhEvqIwHCkiijGqZhTS3KmGFeBopaR+dJVBRBMoXwzk4B3Hn
0Zib1dEYFZa84vPJZyvxCbLOnPRDJgH6V2uQqbG+6DXVaf/wORVOvF/wzzv0viM/
RWbEtJZdvo8N3sdtCULzifnxP/V0T9+4ZQ==
-----END CERTIFICATE-----
+# "AffirmTrust Commercial"
+# 03 76 AB 1D 54 C5 F9 80 3C E4 B2 E2 01 A0 EE 7E
+# EF 7B 57 B6 36 E8 A9 3C 9B 8D 48 60 C9 6F 5F A7
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIId3cGJyapsXwwDQYJKoZIhvcNAQELBQAwRDELMAkGA1UE
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
@@ -173,6 +231,9 @@ Z8SOyUOyXGsViQK8YvxO8rUzqrJv0wqiUOP2O+guRMLbZjipM1ZI8W0bM40NjD9g
N53Tym1+NH4Nn3J2ixufcv1SNUFFApYvHLKac0khsUlHRUe072o0EclNmsxZt9YC
nlpOZbWUrhvfKbAW8b8Angc6F2S1BLUjIZkKlTuXfO8=
-----END CERTIFICATE-----
+# "AffirmTrust Networking"
+# 0A 81 EC 5A 92 97 77 F1 45 90 4A F3 8D 5D 50 9F
+# 66 B5 E2 C5 8F CD B5 31 05 8B 0E 17 F3 F0 B4 1B
-----BEGIN CERTIFICATE-----
MIIDTDCCAjSgAwIBAgIIfE8EORzUmS0wDQYJKoZIhvcNAQEFBQAwRDELMAkGA1UE
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MR8wHQYDVQQDDBZBZmZpcm1UcnVz
@@ -193,19 +254,9 @@ Lgo/bNjR9eUJtGxUAArgFU2HdW23WJZa3W3SAKD0m0i+wzekujbgfIeFlxoVot4u
olu9rxj5kFDNcFn4J2dHy8egBzp90SxdbBk6ZrV9/ZFvgrG+CJPbFEfxojfHRZ48
x3evZKiT3/Zpg4Jg8klCNO1aAFSFHBY2kgxc+qatv9s=
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
-VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
-cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
-BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
-VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
-0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
-ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
-A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
-aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
-flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
------END CERTIFICATE-----
+# "AffirmTrust Premium"
+# 70 A7 3F 7F 37 6B 60 07 42 48 90 45 34 B1 14 82
+# D5 BF 0E 69 8E CC 49 8D F5 25 77 EB F2 E9 3B 9A
-----BEGIN CERTIFICATE-----
MIIFRjCCAy6gAwIBAgIIbYwURrGmCu4wDQYJKoZIhvcNAQEMBQAwQTELMAkGA1UE
BhMCVVMxFDASBgNVBAoMC0FmZmlybVRydXN0MRwwGgYDVQQDDBNBZmZpcm1UcnVz
@@ -237,6 +288,113 @@ GKa1qF60g2xraUDTn9zxw2lrueFtCfTxqlB2Cnp9ehehVZZCmTEJ3WARjQUwfuaO
RtGdFNrHF+QFlozEJLUbzxQHskD4o55BhrwE0GuWyCqANP2/7waj3VjFhT0+j/6e
KeC2uAloGRwYQw==
-----END CERTIFICATE-----
+# "AffirmTrust Premium ECC"
+# BD 71 FD F6 DA 97 E4 CF 62 D1 64 7A DD 25 81 B0
+# 7D 79 AD F8 39 7E B4 EC BA 9C 5E 84 88 82 14 23
+-----BEGIN CERTIFICATE-----
+MIIB/jCCAYWgAwIBAgIIdJclisc/elQwCgYIKoZIzj0EAwMwRTELMAkGA1UEBhMC
+VVMxFDASBgNVBAoMC0FmZmlybVRydXN0MSAwHgYDVQQDDBdBZmZpcm1UcnVzdCBQ
+cmVtaXVtIEVDQzAeFw0xMDAxMjkxNDIwMjRaFw00MDEyMzExNDIwMjRaMEUxCzAJ
+BgNVBAYTAlVTMRQwEgYDVQQKDAtBZmZpcm1UcnVzdDEgMB4GA1UEAwwXQWZmaXJt
+VHJ1c3QgUHJlbWl1bSBFQ0MwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAAQNMF4bFZ0D
+0KF5Nbc6PJJ6yhUczWLznCZcBz3lVPqj1swS6vQUX+iOGasvLkjmrBhDeKzQN8O9
+ss0s5kfiGuZjuD0uL3jET9v0D6RoTFVya5UdThhClXjMNzyR4ptlKymjQjBAMB0G
+A1UdDgQWBBSaryl6wBE1NSZRMADDav5A1a7WPDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAKBggqhkjOPQQDAwNnADBkAjAXCfOHiFBar8jAQr9HX/Vs
+aobgxCd05DhT1wV/GzTjxi+zygk8N53X57hG8f2h4nECMEJZh0PUUd+60wkyWs6I
+flc9nF9Ca/UHLbXwgpP5WW+uZPpY5Yse42O+tYHNbwKMeQ==
+-----END CERTIFICATE-----
+# "Amazon Root CA 1"
+# 8E CD E6 88 4F 3D 87 B1 12 5B A3 1A C3 FC B1 3D
+# 70 16 DE 7F 57 CC 90 4F E1 CB 97 C6 AE 98 19 6E
+-----BEGIN CERTIFICATE-----
+MIIDQTCCAimgAwIBAgITBmyfz5m/jAo54vB4ikPmljZbyjANBgkqhkiG9w0BAQsF
+ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
+b24gUm9vdCBDQSAxMB4XDTE1MDUyNjAwMDAwMFoXDTM4MDExNzAwMDAwMFowOTEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
+b3QgQ0EgMTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALJ4gHHKeNXj
+ca9HgFB0fW7Y14h29Jlo91ghYPl0hAEvrAIthtOgQ3pOsqTQNroBvo3bSMgHFzZM
+9O6II8c+6zf1tRn4SWiw3te5djgdYZ6k/oI2peVKVuRF4fn9tBb6dNqcmzU5L/qw
+IFAGbHrQgLKm+a/sRxmPUDgH3KKHOVj4utWp+UhnMJbulHheb4mjUcAwhmahRWa6
+VOujw5H5SNz/0egwLX0tdHA114gk957EWW67c4cX8jJGKLhD+rcdqsq08p8kDi1L
+93FcXmn/6pUCyziKrlA4b9v7LWIbxcceVOF34GfID5yHI9Y/QCB/IIDEgEw+OyQm
+jgSubJrIqg0CAwEAAaNCMEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AYYwHQYDVR0OBBYEFIQYzIU07LwMlJQuCFmcx7IQTgoIMA0GCSqGSIb3DQEBCwUA
+A4IBAQCY8jdaQZChGsV2USggNiMOruYou6r4lK5IpDB/G/wkjUu0yKGX9rbxenDI
+U5PMCCjjmCXPI6T53iHTfIUJrU6adTrCC2qJeHZERxhlbI1Bjjt/msv0tadQ1wUs
+N+gDS63pYaACbvXy8MWy7Vu33PqUXHeeE6V/Uq2V8viTO96LXFvKWlJbYK8U90vv
+o/ufQJVtMVT8QtPHRh8jrdkPSHCa2XV4cdFyQzR1bldZwgJcJmApzyMZFo6IQ6XU
+5MsI+yMRQ+hDKXJioaldXgjUkK642M4UwtBV8ob2xJNDd2ZhwLnoQdeXeGADbkpy
+rqXRfboQnoZsG4q5WTP468SQvvG5
+-----END CERTIFICATE-----
+# "Amazon Root CA 2"
+# 1B A5 B2 AA 8C 65 40 1A 82 96 01 18 F8 0B EC 4F
+# 62 30 4D 83 CE C4 71 3A 19 C3 9C 01 1E A4 6D B4
+-----BEGIN CERTIFICATE-----
+MIIFQTCCAymgAwIBAgITBmyf0pY1hp8KD+WGePhbJruKNzANBgkqhkiG9w0BAQwF
+ADA5MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6
+b24gUm9vdCBDQSAyMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTEL
+MAkGA1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJv
+b3QgQ0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAK2Wny2cSkxK
+gXlRmeyKy2tgURO8TW0G/LAIjd0ZEGrHJgw12MBvIITplLGbhQPDW9tK6Mj4kHbZ
+W0/jTOgGNk3Mmqw9DJArktQGGWCsN0R5hYGCrVo34A3MnaZMUnbqQ523BNFQ9lXg
+1dKmSYXpN+nKfq5clU1Imj+uIFptiJXZNLhSGkOQsL9sBbm2eLfq0OQ6PBJTYv9K
+8nu+NQWpEjTj82R0Yiw9AElaKP4yRLuH3WUnAnE72kr3H9rN9yFVkE8P7K6C4Z9r
+2UXTu/Bfh+08LDmG2j/e7HJV63mjrdvdfLC6HM783k81ds8P+HgfajZRRidhW+me
+z/CiVX18JYpvL7TFz4QuK/0NURBs+18bvBt+xa47mAExkv8LV/SasrlX6avvDXbR
+8O70zoan4G7ptGmh32n2M8ZpLpcTnqWHsFcQgTfJU7O7f/aS0ZzQGPSSbtqDT6Zj
+mUyl+17vIWR6IF9sZIUVyzfpYgwLKhbcAS4y2j5L9Z469hdAlO+ekQiG+r5jqFoz
+7Mt0Q5X5bGlSNscpb/xVA1wf+5+9R+vnSUeVC06JIglJ4PVhHvG/LopyboBZ/1c6
++XUyo05f7O0oYtlNc/LMgRdg7c3r3NunysV+Ar3yVAhU/bQtCSwXVEqY0VThUWcI
+0u1ufm8/0i2BWSlmy5A5lREedCf+3euvAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMB
+Af8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSwDPBMMPQFWAJI/TPlUq9LhONm
+UjANBgkqhkiG9w0BAQwFAAOCAgEAqqiAjw54o+Ci1M3m9Zh6O+oAA7CXDpO8Wqj2
+LIxyh6mx/H9z/WNxeKWHWc8w4Q0QshNabYL1auaAn6AFC2jkR2vHat+2/XcycuUY
++gn0oJMsXdKMdYV2ZZAMA3m3MSNjrXiDCYZohMr/+c8mmpJ5581LxedhpxfL86kS
+k5Nrp+gvU5LEYFiwzAJRGFuFjWJZY7attN6a+yb3ACfAXVU3dJnJUH/jWS5E4ywl
+7uxMMne0nxrpS10gxdr9HIcWxkPo1LsmmkVwXqkLN1PiRnsn/eBG8om3zEK2yygm
+btmlyTrIQRNg91CMFa6ybRoVGld45pIq2WWQgj9sAq+uEjonljYE1x2igGOpm/Hl
+urR8FLBOybEfdF849lHqm/osohHUqS0nGkWxr7JOcQ3AWEbWaQbLU8uz/mtBzUF+
+fUwPfHJ5elnNXkoOrJupmHN5fLT0zLm4BwyydFy4x2+IoZCn9Kr5v2c69BoVYh63
+n749sSmvZ6ES8lgQGVMDMBu4Gon2nL2XA46jCfMdiyHxtN/kHNGfZQIG6lzWE7OE
+76KlXIx3KadowGuuQNKotOrN8I1LOJwZmhsoVLiJkO/KdYE+HvJkJMcYr07/R54H
+9jVlpNMKVv/1F2Rs76giJUmTtt8AF9pYfl3uxRuw0dFfIRDH+fO6AgonB8Xx1sfT
+4PsJYGw=
+-----END CERTIFICATE-----
+# "Amazon Root CA 3"
+# 18 CE 6C FE 7B F1 4E 60 B2 E3 47 B8 DF E8 68 CB
+# 31 D0 2E BB 3A DA 27 15 69 F5 03 43 B4 6D B3 A4
+-----BEGIN CERTIFICATE-----
+MIIBtjCCAVugAwIBAgITBmyf1XSXNmY/Owua2eiedgPySjAKBggqhkjOPQQDAjA5
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
+Um9vdCBDQSAzMB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
+A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
+Q0EgMzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABCmXp8ZBf8ANm+gBG1bG8lKl
+ui2yEujSLtf6ycXYqm0fc4E7O5hrOXwzpcVOho6AF2hiRVd9RFgdszflZwjrZt6j
+QjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMB0GA1UdDgQWBBSr
+ttvXBp43rDCGB5Fwx5zEGbF4wDAKBggqhkjOPQQDAgNJADBGAiEA4IWSoxe3jfkr
+BqWTrBqYaGFy+uGh0PsceGCmQ5nFuMQCIQCcAu/xlJyzlvnrxir4tiz+OpAUFteM
+YyRIHN8wfdVoOw==
+-----END CERTIFICATE-----
+# "Amazon Root CA 4"
+# E3 5D 28 41 9E D0 20 25 CF A6 90 38 CD 62 39 62
+# 45 8D A5 C6 95 FB DE A3 C2 2B 0B FB 25 89 70 92
+-----BEGIN CERTIFICATE-----
+MIIB8jCCAXigAwIBAgITBmyf18G7EEwpQ+Vxe3ssyBrBDjAKBggqhkjOPQQDAzA5
+MQswCQYDVQQGEwJVUzEPMA0GA1UEChMGQW1hem9uMRkwFwYDVQQDExBBbWF6b24g
+Um9vdCBDQSA0MB4XDTE1MDUyNjAwMDAwMFoXDTQwMDUyNjAwMDAwMFowOTELMAkG
+A1UEBhMCVVMxDzANBgNVBAoTBkFtYXpvbjEZMBcGA1UEAxMQQW1hem9uIFJvb3Qg
+Q0EgNDB2MBAGByqGSM49AgEGBSuBBAAiA2IABNKrijdPo1MN/sGKe0uoe0ZLY7Bi
+9i0b2whxIdIA6GO9mif78DluXeo9pcmBqqNbIJhFXRbb/egQbeOc4OO9X4Ri83Bk
+M6DLJC9wuoihKqB1+IGuYgbEgds5bimwHvouXKNCMEAwDwYDVR0TAQH/BAUwAwEB
+/zAOBgNVHQ8BAf8EBAMCAYYwHQYDVR0OBBYEFNPsxzplbszh2naaVvuc84ZtV+WB
+MAoGCCqGSM49BAMDA2gAMGUCMDqLIfG9fhGt0O9Yli/W651+kI0rz2ZVwyzjKKlw
+CkcO8DdZEv8tmZQoTipPNU0zWgIxAOp1AE47xDqUEpHJWEadIRNyp4iciuRMStuW
+1KyLa2tJElMzrdfkviT8tQp21KW8EA==
+-----END CERTIFICATE-----
+# "ANF Global Root CA"
+# E3 26 8F 61 06 BA 8B 66 5A 1A 96 2D DE A1 45 9D
+# 2A 46 97 2F 1F 24 40 32 9B 39 0B 89 57 49 AD 45
-----BEGIN CERTIFICATE-----
MIIIGDCCBgCgAwIBAgIGAT8vMXfmMA0GCSqGSIb3DQEBCwUAMIIBCjELMAkGA1UE
BhMCRVMxEjAQBgNVBAgMCUJhcmNlbG9uYTFYMFYGA1UEBwxPQmFyY2Vsb25hIChz
@@ -283,6 +441,40 @@ hxfggTvRCk4w79cUID45c2qDsRCqTPoOo/cbOpcfVhbH9LdMORpmuLwNogRZEUSE
fWpqR9q+0kcQf4zGSWIURIyDrogdpDgoHDxktqgMgc+qA4ZE2WQl1D8hmev53A46
lUSrWUiWfDXtK3ux
-----END CERTIFICATE-----
+# "Apple Root CA"
+# B0 B1 73 0E CB C7 FF 45 05 14 2C 49 F1 29 5E 6E
+# DA 6B CA ED 7E 2C 68 C5 BE 91 B5 A1 10 01 F0 24
+-----BEGIN CERTIFICATE-----
+MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
+MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
+biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
+MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
+bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
+FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
++FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
+XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
+tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
+q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
+aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
+BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
+R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
+ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
+d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
+IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
+YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
+b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
+Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
+NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
+y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
+R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
+xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
+IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
+UKqK1drk/NAJBzewdXUh
+-----END CERTIFICATE-----
+# "Apple Root CA - G2"
+# C2 B9 B0 42 DD 57 83 0E 7D 11 7D AC 55 AC 8A E1
+# 94 07 D3 8E 41 D8 8F 32 15 BC 3A 89 04 44 A0 50
-----BEGIN CERTIFICATE-----
MIIFkjCCA3qgAwIBAgIIAeDltYNno+AwDQYJKoZIhvcNAQEMBQAwZzEbMBkGA1UE
AwwSQXBwbGUgUm9vdCBDQSAtIEcyMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0
@@ -315,6 +507,9 @@ Tta6SqoWqPQFZ2aWuuJVecMsXUmPgEkrihLHdoBR37q9ZV0+N0djMenl9MU/S60E
inpxLK8JQzcPqOMyT/RFtm2XNuyE9QoB6he7hY1Ck3DDUOUUi78/w0EP3SIEIwiK
um1xRKtzCTrJ+VKACd+66eYWyi4uTLLT3OUEVLLUNIAytbwPF+E=
-----END CERTIFICATE-----
+# "Apple Root CA - G3"
+# 63 34 3A BF B8 9A 6A 03 EB B5 7E 9B 3F 5F A7 BE
+# 7C 4F 5C 75 6F 30 17 B3 A8 C4 88 C3 65 3E 91 79
-----BEGIN CERTIFICATE-----
MIICQzCCAcmgAwIBAgIILcX8iNLFS5UwCgYIKoZIzj0EAwMwZzEbMBkGA1UEAwwS
QXBwbGUgUm9vdCBDQSAtIEczMSYwJAYDVQQLDB1BcHBsZSBDZXJ0aWZpY2F0aW9u
@@ -330,34 +525,9 @@ MGUCMQCD6cHEFl4aXTQY2e3v9GwOAEZLuN+yRhHFD/3meoyhpmvOwgPUnPWTxnS4
at+qIxUCMG1mihDK1A3UT82NQz60imOlM27jbdoXt2QfyFMm+YhidDkLF1vLUagM
6BgD56KyKA==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEuzCCA6OgAwIBAgIBAjANBgkqhkiG9w0BAQUFADBiMQswCQYDVQQGEwJVUzET
-MBEGA1UEChMKQXBwbGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlv
-biBBdXRob3JpdHkxFjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwHhcNMDYwNDI1MjE0
-MDM2WhcNMzUwMjA5MjE0MDM2WjBiMQswCQYDVQQGEwJVUzETMBEGA1UEChMKQXBw
-bGUgSW5jLjEmMCQGA1UECxMdQXBwbGUgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkx
-FjAUBgNVBAMTDUFwcGxlIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
-ggEKAoIBAQDkkakJH5HbHkdQ6wXtXnmELes2oldMVeyLGYne+Uts9QerIjAC6Bg+
-+FAJ039BqJj50cpmnCRrEdCju+QbKsMflZ56DKRHi1vUFjczy8QPTc4UadHJGXL1
-XQ7Vf1+b8iUDulWPTV0N8WQ1IxVLFVkds5T39pyez1C6wVhQZ48ItCD3y6wsIG9w
-tj8BMIy3Q88PnT3zK0koGsj+zrW5DtleHNbLPbU6rfQPDgCSC7EhFi501TwN22IW
-q6NxkkdTVcGvL0Gz+PvjcM3mo0xFfh9Ma1CWQYnEdGILEINBhzOKgbEwWOxaBDKM
-aLOPHd5lc/9nXmW8Sdh2nzMUZaF3lMktAgMBAAGjggF6MIIBdjAOBgNVHQ8BAf8E
-BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUK9BpR5R2Cf70a40uQKb3
-R01/CF4wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/CF4wggERBgNVHSAE
-ggEIMIIBBDCCAQAGCSqGSIb3Y2QFATCB8jAqBggrBgEFBQcCARYeaHR0cHM6Ly93
-d3cuYXBwbGUuY29tL2FwcGxlY2EvMIHDBggrBgEFBQcCAjCBthqBs1JlbGlhbmNl
-IG9uIHRoaXMgY2VydGlmaWNhdGUgYnkgYW55IHBhcnR5IGFzc3VtZXMgYWNjZXB0
-YW5jZSBvZiB0aGUgdGhlbiBhcHBsaWNhYmxlIHN0YW5kYXJkIHRlcm1zIGFuZCBj
-b25kaXRpb25zIG9mIHVzZSwgY2VydGlmaWNhdGUgcG9saWN5IGFuZCBjZXJ0aWZp
-Y2F0aW9uIHByYWN0aWNlIHN0YXRlbWVudHMuMA0GCSqGSIb3DQEBBQUAA4IBAQBc
-NplMLXi37Yyb3PN3m/J20ncwT8EfhYOFG5k9RzfyqZtAjizUsZAS2L70c5vu0mQP
-y3lPNNiiPvl4/2vIB+x9OYOLUyDTOMSxv5pPCmv/K/xZpwUJfBdAVhEedNO3iyM7
-R6PVbyTi69G3cN8PReEnyvFteO3ntRcXqNx+IjXKJdXZD9Zr1KIkIxH3oayPc4Fg
-xhtbCS+SsvhESPBgOJ4V9T0mZyCKM2r3DYLP3uujL/lTaltkwGMzd/c6ByxW69oP
-IQ7aunMZT7XZNn/Bh1XZp5m5MkL72NVxnn6hUrcbvZNCJBIqxw8dtk2cXmPIS4AX
-UKqK1drk/NAJBzewdXUh
------END CERTIFICATE-----
+# "Apple Root Certificate Authority"
+# 0D 83 B6 11 B6 48 A1 A7 5E B8 55 84 00 79 53 75
+# CA D9 2E 26 4E D8 E9 D7 A7 57 C1 F5 EE 2B B2 2D
-----BEGIN CERTIFICATE-----
MIIFujCCBKKgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBhjELMAkGA1UEBhMCVVMx
HTAbBgNVBAoTFEFwcGxlIENvbXB1dGVyLCBJbmMuMS0wKwYDVQQLEyRBcHBsZSBD
@@ -391,6 +561,9 @@ Hld2j383LS4CXN1jyfJxuCZA3xWNdUQ/eb3mHZnhQyw+rW++uaT+DjUZUWOxw961
kj5ReAFziqQjyqSI8R5cH0EWLX6VCqrpiUGYGxrdyyC/R14MJsVVNU3GMIuZZxTH
CR+6R8faAQmHJEKVvRNgGQrv6n8Obs3BREM6StXj
-----END CERTIFICATE-----
+# "ApplicationCA2 Root"
+# 12 6B F0 1C 10 94 D2 F0 CA 2E 35 23 80 B3 C7 24
+# 29 45 46 CC C6 55 97 BE F7 F1 2D 8A 17 1F 19 84
-----BEGIN CERTIFICATE-----
MIID9zCCAt+gAwIBAgILMTI1MzcyODI4MjgwDQYJKoZIhvcNAQELBQAwWDELMAkG
A1UEBhMCSlAxHDAaBgNVBAoTE0phcGFuZXNlIEdvdmVybm1lbnQxDTALBgNVBAsT
@@ -415,6 +588,9 @@ Bcx4m+mB26jIx1ye/JKSLaaX8ji1bnOVDMA/zqaUMLX6BbfeniCq/BNkyYq6ZO/i
Y+TYmK5rtT6mVbgzPixy+ywRAPtbFi+E0hOe+gXFwctyTiLdhMpLvNIthhoEdlkf
SUJiOxMfFui61/0=
-----END CERTIFICATE-----
+# "Atos TrustedRoot 2011"
+# F3 56 BE A2 44 B7 A9 1E B3 5D 53 CA 9A D7 86 4A
+# CE 01 8E 2D 35 D5 F8 F9 6D DF 68 A6 F4 1A A4 74
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIIXDPLYixfszIwDQYJKoZIhvcNAQELBQAwPDEeMBwGA1UE
AwwVQXRvcyBUcnVzdGVkUm9vdCAyMDExMQ0wCwYDVQQKDARBdG9zMQswCQYDVQQG
@@ -436,6 +612,9 @@ maHFCN795trV1lpFDMS3wrUU77QR/w4VtfX128a961qn8FYiqTxlVMYVqL2Gns2D
lmh6cYGJ4Qvh6hEbaAjMaZ7snkGeRDImeuKHCnE96+RapNLbxc3G3mB/ufNPRJLv
KrcYPqcZ2Qt9sTdBQrC6YB3y/gkRsPCHe6ed
-----END CERTIFICATE-----
+# "Autoridad de Certificacion Firmaprofesional CIF A62634068"
+# 04 04 80 28 BF 1F 28 64 D4 8F 9A D4 D8 32 94 36
+# 6A 82 88 56 55 3F 3B 14 30 3F 90 14 7F 5D 40 EF
-----BEGIN CERTIFICATE-----
MIIGFDCCA/ygAwIBAgIIU+w77vuySF8wDQYJKoZIhvcNAQEFBQAwUTELMAkGA1UE
BhMCRVMxQjBABgNVBAMMOUF1dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIEZpcm1h
@@ -471,6 +650,9 @@ StRf571oe2XyFR7SOqkt6dhrJKyXWERHrVkY8SFlcN7ONGCoQPHzPKTDKCOM/icz
Q0CgFzzr6juwcqajuUpLXhZI9LK8yIySxZ2frHI2vDSANGupi5LAuBft7HZT9SQB
jLMi6Et8Vcad+qMUu2WFbm5PEn4KPJ2V
-----END CERTIFICATE-----
+# "Autoridad de Certificacion Raiz del Estado Venezolano"
+# 0E D3 FF AB 6C 14 9C 8B 4E 71 05 8E 86 68 D4 29
+# AB FD A6 81 C2 FF F5 08 20 76 41 F0 D7 51 A3 E5
-----BEGIN CERTIFICATE-----
MIIJmzCCB4OgAwIBAgIBATANBgkqhkiG9w0BAQwFADCCAR4xPjA8BgNVBAMTNUF1
dG9yaWRhZCBkZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9s
@@ -525,6 +707,9 @@ bqAXWmk46SwIdWRPLLqbUpDTKooynZKpSYIkkotdgJoVZUUCY+RCO8jsVPEU6ece
SxztNUm5UOta1OJPMwSAKRHOo3ilVb9c6lAixDdvV8MeNbqe6asM1mpCHWbJ/0rg
5Ls9Cxx8hracyp0ev7b0
-----END CERTIFICATE-----
+# "Baltimore CyberTrust Root"
+# 16 AF 57 A9 F6 76 B0 AB 12 60 95 AA 5E BA DE F2
+# 2A B3 11 19 D6 44 AC 95 CD 4B 93 DB F3 F2 6A EB
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIEAgAAuTANBgkqhkiG9w0BAQUFADBaMQswCQYDVQQGEwJJ
RTESMBAGA1UEChMJQmFsdGltb3JlMRMwEQYDVQQLEwpDeWJlclRydXN0MSIwIAYD
@@ -546,6 +731,9 @@ Epn3o0WC4zxe9Z2etciefC7IpJ5OCBRLbf1wbWsaY71k5h+3zvDyny67G7fyUIhz
ksLi4xaNmjICq44Y3ekQEe5+NauQrz4wlHrQMz2nZQ/1/I6eYs9HRCwBXbsdtTLS
R9I4LtD+gdwyah617jzV/OeBHRnDJELqYzmp
-----END CERTIFICATE-----
+# "Belgium Root CA2"
+# 9F 97 44 46 3B E1 37 14 75 4E 1A 3B EC F9 8C 08
+# CC 20 5E 4A B3 20 28 F4 E2 83 0C 4A 1B 27 75 B8
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIIKv++n6Lw6YcwDQYJKoZIhvcNAQEFBQAwKDELMAkGA1UE
BhMCQkUxGTAXBgNVBAMTEEJlbGdpdW0gUm9vdCBDQTIwHhcNMDcxMDA0MTAwMDAw
@@ -568,6 +756,9 @@ KvPG2F9fVJ3bTc0R5/0UAoNmXsimABKgX77OFP67H6dh96tK8QYUn8pJQsKpvO2F
sauBQeYNxUJpU4c5nUwfAA4+Bw11V0SoU7Q2dmSZ3G7rPUZuFF1eR1ONeE3gJ7uO
hXY=
-----END CERTIFICATE-----
+# "Buypass Class 2 Root CA"
+# 9A 11 40 25 19 7C 5B B9 5D 94 E6 3D 55 CD 43 79
+# 08 47 B6 46 B2 3C DF 11 AD A4 A0 0E FF 15 FB 48
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
@@ -599,6 +790,9 @@ I+uUWnpp3Q+/QFesa1lQ2aOZ4W7+jQF5JyMV3pKdewlNWudLSDBaGOYKbeaP4NK7
3PFaTWwyI0PurKju7koSCTxdccK+efrCh2gdC/1cacwG0Jp9VJkqyTkaGa9LKkPz
Y11aWOIv4x3kqdbQCtCev9eBCfHJxyYNrJgWVqA=
-----END CERTIFICATE-----
+# "Buypass Class 3 Root CA"
+# ED F7 EB BC A2 7A 2A 38 4D 38 7B 7D 40 10 C6 66
+# E2 ED B4 84 3E 4C 29 B4 AE 1D 5B 93 32 E6 B2 4D
-----BEGIN CERTIFICATE-----
MIIFWTCCA0GgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJOTzEd
MBsGA1UECgwUQnV5cGFzcyBBUy05ODMxNjMzMjcxIDAeBgNVBAMMF0J1eXBhc3Mg
@@ -630,6 +824,9 @@ kbIRNBE+6tBDGR8Dk5AM/1E9V/RBbuHLoL7ryWPNbczk+DaqaJ3tvV2XcEQNtg41
u79leNKGef9JOxqDDPDeeOzI8k1MGt6CKfjBWtrt7uYnXuhF0J0cUahoq0Tj0Itq
4/g7u9xN12TyUb7mqqta6THuBrxzvxNiCp/HuZc=
-----END CERTIFICATE-----
+# "CA Disig Root R1"
+# F9 6F 23 F4 C3 E7 9C 07 7A 46 98 8D 5A F5 90 06
+# 76 A0 F0 39 CB 64 5D D1 75 49 B2 16 C8 24 40 CE
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNV
BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
@@ -661,6 +858,9 @@ F7mGnjixlAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqF
a3qdnom2piiZk4hA9z7NUaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsT
Q6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJa7+h89n07eLw4+1knj0vllJPgFOL
-----END CERTIFICATE-----
+# "CA Disig Root R2"
+# E2 3D 4A 03 6D 7B 70 E9 F5 95 B1 42 20 79 D2 B9
+# 1E DF BB 1F B6 51 A0 63 3E AA 8A 9D C5 F8 07 03
-----BEGIN CERTIFICATE-----
MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNV
BAYTAlNLMRMwEQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMu
@@ -692,6 +892,9 @@ G5gPcFw0sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3Os
zMOl6W8KjptlwlCFtaOgUxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8x
L4ysEr3vQCj8KWefshNPZiTEUxnpHikV7+ZtsH8tZ/3zbBt1RqPlShfppNcL
-----END CERTIFICATE-----
+# "Certigna"
+# E3 B6 A2 DB 2E D7 CE 48 84 2F 7A C5 32 41 C7 B7
+# 1D 54 14 4B FB 40 C1 1F 3F 1D 0B 42 F5 EE A1 2D
-----BEGIN CERTIFICATE-----
MIIDqDCCApCgAwIBAgIJAP7c4wEPyUj/MA0GCSqGSIb3DQEBBQUAMDQxCzAJBgNV
BAYTAkZSMRIwEAYDVQQKDAlEaGlteW90aXMxETAPBgNVBAMMCENlcnRpZ25hMB4X
@@ -714,6 +917,9 @@ HWhBp6pX6FOqB9IG9tUUBguRA3UsbHK1YZWaDYu5Def131TN3ubY1gkIl2PlwS6w
t0QmwCbAr1UwnjvVNioZBPRcHv/PLLf/0P2HQBHVESO7SMAhqaQoLf0V+LBOK/Qw
WyH8EZE0vkHve52Xdf+XlcCWWC/qu0bXu+TZLg==
-----END CERTIFICATE-----
+# "Certinomis - Autorité Racine"
+# FC BF E2 88 62 06 F7 2B 27 59 3C 8B 07 02 97 E1
+# 2D 76 9E D1 0E D7 93 07 05 A8 09 8E FF C1 4D 17
-----BEGIN CERTIFICATE-----
MIIFnDCCA4SgAwIBAgIBATANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJGUjET
MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxJjAk
@@ -746,6 +952,9 @@ pdEdnV1j6CTmNhTih60bWfVEm/vXd3wfAXBioSAaosUaKPQhA+4u2cGA6rnZgtZb
dsLLO7XSAPCjDuGtbkD326C00EauFddEwk01+dIL8hf2rGbVJLJP0RyZwG71fet0
BLj5TXcJ17TPBzAJ8bgAVtkXFhYKK4bfjwEZGuW7gmP/vgt2Fl43N+bYdJeimUV5
-----END CERTIFICATE-----
+# "Certinomis - Root CA"
+# 2A 99 F5 BC 11 74 B7 3C BB 1D 62 08 84 E0 1C 34
+# E5 1C CB 39 78 DA 12 5F 0E 33 26 88 83 BF 41 58
-----BEGIN CERTIFICATE-----
MIIFkjCCA3qgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJGUjET
MBEGA1UEChMKQ2VydGlub21pczEXMBUGA1UECxMOMDAwMiA0MzM5OTg5MDMxHTAb
@@ -778,6 +987,60 @@ Y/M50n92Uaf0yKHxDHYiI0ZSKS3io0EHVmmY0gUJvGnHWmHNj4FgFU2A3ZDifcRQ
8ow7bkrHxuaAKzyBvBGAFhAn1/DNP3nMcyrDflOR1m749fPH0FFNjkulW+YZFzvW
gQncItzujrnEj1PhZ7szuIgVRs/taTX/dQ1G885x4cVrhkIGuUE=
-----END CERTIFICATE-----
+# "Certplus Root CA G1"
+# 15 2A 40 2B FC DF 2C D5 48 05 4D 22 75 B3 9C 7F
+# CA 3E C0 97 80 78 B0 F0 EA 76 E5 61 A6 C7 43 3E
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgISESBVg+QtPlRWhS2DN7cs3EYRMA0GCSqGSIb3DQEBDQUA
+MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
+dHBsdXMgUm9vdCBDQSBHMTAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBa
+MD4xCzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2Vy
+dHBsdXMgUm9vdCBDQSBHMTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIB
+ANpQh7bauKk+nWT6VjOaVj0W5QOVsjQcmm1iBdTYj+eJZJ+622SLZOZ5KmHNr49a
+iZFluVj8tANfkT8tEBXgfs+8/H9DZ6itXjYj2JizTfNDnjl8KvzsiNWI7nC9hRYt
+6kuJPKNxQv4c/dMcLRC4hlTqQ7jbxofaqK6AJc96Jh2qkbBIb6613p7Y1/oA/caP
+0FG7Yn2ksYyy/yARujVjBYZHYEMzkPZHogNPlk2dT8Hq6pyi/jQu3rfKG3akt62f
+6ajUeD94/vI4CTYd0hYCyOwqaK/1jpTvLRN6HkJKHRUxrgwEV/xhc/MxVoYxgKDE
+EW4wduOU8F8ExKyHcomYxZ3MVwia9Az8fXoFOvpHgDm2z4QTd28n6v+WZxcIbekN
+1iNQMLAVdBM+5S//Ds3EC0pd8NgAM0lm66EYfFkuPSi5YXHLtaW6uOrc4nBvCGrc
+h2c0798wct3zyT8j/zXhviEpIDCB5BmlIOklynMxdCm+4kLV87ImZsdo/Rmz5yCT
+mehd4F6H50boJZwKKSTUzViGUkAksnsPmBIgJPaQbEfIDbsYIC7Z/fyL8inqh3SV
+4EJQeIQEQWGw9CEjjy3LKCHyamz0GqbFFLQ3ZU+V/YDI+HLlJWvEYLF7bY5KinPO
+WftwenMGE9nTdDckQQoRb5fc5+R+ob0V8rqHDz1oihYHAgMBAAGjYzBhMA4GA1Ud
+DwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSowcCbkahDFXxd
+Bie0KlHYlwuBsTAfBgNVHSMEGDAWgBSowcCbkahDFXxdBie0KlHYlwuBsTANBgkq
+hkiG9w0BAQ0FAAOCAgEAnFZvAX7RvUz1isbwJh/k4DgYzDLDKTudQSk0YcbX8ACh
+66Ryj5QXvBMsdbRX7gp8CXrc1cqh0DQT+Hern+X+2B50ioUHj3/MeXrKls3N/U/7
+/SMNkPX0XtPGYX2eEeAC7gkE2Qfdpoq3DIMku4NQkv5gdRE+2J2winq14J2by5BS
+S7CTKtQ+FjPlnsZlFT5kOwQ/2wyPX1wdaR+v8+khjPPvl/aatxm2hHSco1S1cE5j
+2FddUyGbQJJD+tZ3VTNPZNX70Cxqjm0lpu+F6ALEUz65noe8zDUa3qHpimOHZR4R
+Kttjd5cUvpoUmRGywO6wT/gUITJDT5+rosuoD6o7BlXGEilXCNQ314cnrUlZp5Gr
+RHpejXDbl85IULFzk/bwg2D5zfHhMf1bfHEhYxQUqq/F3pN+aLHsIqKqkHWetUNy
+6mSjhEv9DKgma3GX7lZjZuhCVPnHHd/Qj1vfyDBviP4NxDMcU6ij/UgQ8uQKTuEV
+V/xuZDDCVRHc6qnNSlSsKWNEz0pAoNZoWRsz+e86i9sgktxChL8Bq4fA1SCC28a5
+g4VCXA9DO2pJNdWY9BW/+mGBDAkgGNLQFwzLSABQ6XaCjGTXOqAHVcweMcDvOrRl
+++O/QmueD6i9a5jc2NvLi6Td11n0bt3+qsOR0C5CB8AMTVPNJLFMWx5R9N/pkvo=
+-----END CERTIFICATE-----
+# "Certplus Root CA G2"
+# 6C C0 50 41 E6 44 5E 74 69 6C 4C FB C9 F8 0F 54
+# 3B 7E AB BB 44 B4 CE 6F 78 7C 6A 99 71 C4 2F 17
+-----BEGIN CERTIFICATE-----
+MIICHDCCAaKgAwIBAgISESDZkc6uo+jF5//pAq/Pc7xVMAoGCCqGSM49BAMDMD4x
+CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
+dXMgUm9vdCBDQSBHMjAeFw0xNDA1MjYwMDAwMDBaFw0zODAxMTUwMDAwMDBaMD4x
+CzAJBgNVBAYTAkZSMREwDwYDVQQKDAhDZXJ0cGx1czEcMBoGA1UEAwwTQ2VydHBs
+dXMgUm9vdCBDQSBHMjB2MBAGByqGSM49AgEGBSuBBAAiA2IABM0PW1aC3/BFGtat
+93nwHcmsltaeTpwftEIRyoa/bfuFo8XlGVzX7qY/aWfYeOKmycTbLXku54uNAm8x
+Ik0G42ByRZ0OQneezs/lf4WbGOT8zC5y0xaTTsqZY1yhBSpsBqNjMGEwDgYDVR0P
+AQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNqDYwJ5jtpMxjwj
+FNiPwyCrKGBZMB8GA1UdIwQYMBaAFNqDYwJ5jtpMxjwjFNiPwyCrKGBZMAoGCCqG
+SM49BAMDA2gAMGUCMHD+sAvZ94OX7PNVHdTcswYO/jOYnYs5kGuUIe22113WTNch
+p+e/IQ8rzfcq3IUHnQIxAIYUFuXcsGXCwI4Un78kFmjlvPl5adytRSv3tjFzzAal
+U5ORGpOucGpnutee5WEaXw==
+-----END CERTIFICATE-----
+# "certSIGN ROOT CA"
+# EA A9 62 C4 FA 4A 6B AF EB E4 15 19 6D 35 1C CD
+# 88 8D 4F 53 F3 FA 8A E6 D7 C4 66 A9 4E 60 42 BB
-----BEGIN CERTIFICATE-----
MIIDODCCAiCgAwIBAgIGIAYFFnACMA0GCSqGSIb3DQEBBQUAMDsxCzAJBgNVBAYT
AlJPMREwDwYDVQQKEwhjZXJ0U0lHTjEZMBcGA1UECxMQY2VydFNJR04gUk9PVCBD
@@ -798,6 +1061,9 @@ Jd1hJyMctTEHBDa0GpC9oHRxUIltvBTjD4au8as+x6AJzKNI0eDbZOeStc+vckNw
i/nDhDwTqn6Sm1dTk/pwwpEOMfmbZ13pljheX7NzTogVZ96edhBiIL5VaZVDADlN
9u6wWk5JRFRYX0KD
-----END CERTIFICATE-----
+# "Certum CA"
+# D8 E0 FE BC 1D B2 E3 8D 00 94 0F 37 D2 7D 41 34
+# 4D 99 3E 73 4B 99 D5 65 6D 97 78 D4 D8 14 36 24
-----BEGIN CERTIFICATE-----
MIIDDDCCAfSgAwIBAgIDAQAgMA0GCSqGSIb3DQEBBQUAMD4xCzAJBgNVBAYTAlBM
MRswGQYDVQQKExJVbml6ZXRvIFNwLiB6IG8uby4xEjAQBgNVBAMTCUNlcnR1bSBD
@@ -817,6 +1083,34 @@ CjqTE5s7FCMTY5w/0YcneeVMUeMBrYVdGjux1XMQpNPyvG5k9VpWkKjHDkx0Dy5x
O/fIR/RpbxXyEV6DHpx8Uq79AtoSqFlnGNu8cN2bsWntgM6JQEhqDjXKKWYVIZQs
6GAqm4VKQPNriiTsBhYscw==
-----END CERTIFICATE-----
+# "Certum Trusted Network CA"
+# 5C 58 46 8D 55 F5 8E 49 7E 74 39 82 D2 B5 00 10
+# B6 D1 65 37 4A CF 83 A7 D4 A3 2D B7 68 C4 40 8E
+-----BEGIN CERTIFICATE-----
+MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
+MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
+ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
+cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
+WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
+Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
+IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
+UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
+TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
+BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
+kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
+AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
+HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
+sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
+I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
+J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
+VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
+03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
+-----END CERTIFICATE-----
+# "Certum Trusted Network CA 2"
+# B6 76 F2 ED DA E8 77 5C D3 6C B0 F6 3C D1 D4 60
+# 39 61 F4 9E 62 65 BA 01 3A 2F 03 07 B6 D0 B8 04
-----BEGIN CERTIFICATE-----
MIIF0jCCA7qgAwIBAgIQIdbQSk8lD8kyN/yqXhKN6TANBgkqhkiG9w0BAQ0FADCB
gDELMAkGA1UEBhMCUEwxIjAgBgNVBAoTGVVuaXpldG8gVGVjaG5vbG9naWVzIFMu
@@ -851,28 +1145,9 @@ XALKLNhvSgfZyTXaQHXyxKcZb55CEJh15pWLYLztxRLXis7VmFxWlgPF7ncGNf/P
5O4/E2Hu29othfDNrp2yGAlFw5Khchf8R7agCyzxxN5DaAhqXzvwdmP7zAYspsbi
DrW5viSP
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDuzCCAqOgAwIBAgIDBETAMA0GCSqGSIb3DQEBBQUAMH4xCzAJBgNVBAYTAlBM
-MSIwIAYDVQQKExlVbml6ZXRvIFRlY2hub2xvZ2llcyBTLkEuMScwJQYDVQQLEx5D
-ZXJ0dW0gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkxIjAgBgNVBAMTGUNlcnR1bSBU
-cnVzdGVkIE5ldHdvcmsgQ0EwHhcNMDgxMDIyMTIwNzM3WhcNMjkxMjMxMTIwNzM3
-WjB+MQswCQYDVQQGEwJQTDEiMCAGA1UEChMZVW5pemV0byBUZWNobm9sb2dpZXMg
-Uy5BLjEnMCUGA1UECxMeQ2VydHVtIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSIw
-IAYDVQQDExlDZXJ0dW0gVHJ1c3RlZCBOZXR3b3JrIENBMIIBIjANBgkqhkiG9w0B
-AQEFAAOCAQ8AMIIBCgKCAQEA4/t9o3K6wvDJFIf1awFO4W5AB7ptJ11/91sts1rH
-UV+rpDKmYYe2bg+G0jACl/jXaVehGDldamR5xgFZrDwxSjh80gTSSyjoIF87B6LM
-TXPb865Px1bVWqeWifrzq2jUI4ZZJ88JJ7ysbnKDHDBy3+Ci6dLhdHUZvSqeexVU
-BBvXQzmtVSjF4hq79MDkrjhJM8x2hZ85RdKknvISjFH4fOQtf/WsX+sWn7Et0brM
-kUJ3TCXJkDhv2/DM+44el1k+1WBO5gUo7Ul5E0u6SNsv+XLTOcr+H9g0cvW0QM8x
-AcPs3hEtF10fuFDRXhmnad4HMyjKUJX5p1TLVIZQRan5SQIDAQABo0IwQDAPBgNV
-HRMBAf8EBTADAQH/MB0GA1UdDgQWBBQIds3LB/8k9sXN7buQvOKEN0Z19zAOBgNV
-HQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQEFBQADggEBAKaorSLOAT2mo/9i0Eidi15y
-sHhE49wcrwn9I0j6vSrEuVUEtRCjjSfeC4Jj0O7eDDd5QVsisrCaQVymcODU0HfL
-I9MA4GxWL+FpDQ3Zqr8hgVDZBqWo/5U30Kr+4rP1mS1FhIrlQgnXdAIv94nYmem8
-J9RHjboNRhx3zxSkHLmkMcScKHQDNP8zGSal6Q10tz6XxnboJ5ajZt3hrvJBW8qY
-VoNzcOSGGtIxQbovvi0TWnZvTuhOgQ4/WwMioBK+ZlgRSssDxLQqKi2WF+A5VLxI
-03YnnZotBqbJ7DnSq9ufmgsnAjUpsUCV5/nonFWIGUbWtzT1fs45mtk48VH3Tyw=
------END CERTIFICATE-----
+# "CFCA EV ROOT"
+# 5C C3 D7 8E 4E 1D 5E 45 54 7A 04 E6 87 3E 64 F9
+# 0C F9 53 6D 1C CC 2E F8 00 F3 55 C4 C5 FD 70 FD
-----BEGIN CERTIFICATE-----
MIIFjTCCA3WgAwIBAgIEGErM1jANBgkqhkiG9w0BAQsFADBWMQswCQYDVQQGEwJD
TjEwMC4GA1UECgwnQ2hpbmEgRmluYW5jaWFsIENlcnRpZmljYXRpb24gQXV0aG9y
@@ -905,6 +1180,40 @@ Ci77o0cOPaYjesYBx4/IXr9tgFa+iiS6M+qf4TIRnvHST4D2G0CvOJ4RUHlzEhLN
AAoACxGV2lZFA4gKn2fQ1XmxqI1AbQ3CekD6819kR5LLU7m7Wc5P/dAVUwHY3+vZ
5nbv0CO7O6l5s9UCKc2Jo5YPSjXnTkLAdc0Hz+Ys63su
-----END CERTIFICATE-----
+# "Chambers of Commerce Root"
+# 0C 25 8A 12 A5 67 4A EF 25 F2 8B A7 DC FA EC EE
+# A3 48 E5 41 E6 F5 CC 4E E6 3B 71 B3 61 60 6A C3
+-----BEGIN CERTIFICATE-----
+MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
+b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
+MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
+ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
+IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
+AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
+unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
+BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
+7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
+0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
+roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
+A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
+aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
+26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
+BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
+EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
+BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
+aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
+AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
+p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
+1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
+XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
+eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
+tGWaIZDgqtCYvDi1czyL+Nw=
+-----END CERTIFICATE-----
+# "Chambers of Commerce Root - 2008"
+# 06 3E 4A FA C4 91 DF D3 32 F3 08 9B 85 42 E9 46
+# 17 D8 93 D7 FE 94 4E 10 A7 93 7E E2 9D 96 93 C0
-----BEGIN CERTIFICATE-----
MIIHTzCCBTegAwIBAgIJAKPaQn6ksa7aMA0GCSqGSIb3DQEBBQUAMIGuMQswCQYD
VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
@@ -947,34 +1256,9 @@ fhiYtUU79nm06PcaewaD+9CL2rvHvRirCG88gGtAPxkZumWK5r7VXNM21+9AUiRg
OGcEMeyP84LG3rlV8zsxkVrctQgVrXYlCg17LofiDKYGvCYQbTed7N14jHyAxfDZ
d0jQ
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEvTCCA6WgAwIBAgIBADANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJFVTEn
-MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
-ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEiMCAGA1UEAxMZQ2hhbWJlcnMg
-b2YgQ29tbWVyY2UgUm9vdDAeFw0wMzA5MzAxNjEzNDNaFw0zNzA5MzAxNjEzNDRa
-MH8xCzAJBgNVBAYTAkVVMScwJQYDVQQKEx5BQyBDYW1lcmZpcm1hIFNBIENJRiBB
-ODI3NDMyODcxIzAhBgNVBAsTGmh0dHA6Ly93d3cuY2hhbWJlcnNpZ24ub3JnMSIw
-IAYDVQQDExlDaGFtYmVycyBvZiBDb21tZXJjZSBSb290MIIBIDANBgkqhkiG9w0B
-AQEFAAOCAQ0AMIIBCAKCAQEAtzZV5aVdGDDg2olUkfzIx1L4L1DZ77F1c2VHfRtb
-unXF/KGIJPov7coISjlUxFF6tdpg6jg8gbLL8bvZkSM/SAFwdakFKq0fcfPJVD0d
-BmpAPrMMhe5cG3nCYsS4No41XQEMIwRHNaqbYE6gZj3LJgqcQKH0XZi/caulAGgq
-7YN6D6IUtdQis4CwPAxaUWktWBiP7Zme8a7ileb2R6jWDA+wWFjbw2Y3npuRVDM3
-0pQcakjJyfKl2qUMI/cjDpwyVV5xnIQFUZot/eZOKjRa3spAN2cMVCFVd9oKDMyX
-roDclDZK9D7ONhMeU+SsTjoF7Nuucpw4i9A5O4kKPnf+dQIBA6OCAUQwggFAMBIG
-A1UdEwEB/wQIMAYBAf8CAQwwPAYDVR0fBDUwMzAxoC+gLYYraHR0cDovL2NybC5j
-aGFtYmVyc2lnbi5vcmcvY2hhbWJlcnNyb290LmNybDAdBgNVHQ4EFgQU45T1sU3p
-26EpW1eLTXYGduHRooowDgYDVR0PAQH/BAQDAgEGMBEGCWCGSAGG+EIBAQQEAwIA
-BzAnBgNVHREEIDAegRxjaGFtYmVyc3Jvb3RAY2hhbWJlcnNpZ24ub3JnMCcGA1Ud
-EgQgMB6BHGNoYW1iZXJzcm9vdEBjaGFtYmVyc2lnbi5vcmcwWAYDVR0gBFEwTzBN
-BgsrBgEEAYGHLgoDATA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY3BzLmNoYW1iZXJz
-aWduLm9yZy9jcHMvY2hhbWJlcnNyb290Lmh0bWwwDQYJKoZIhvcNAQEFBQADggEB
-AAxBl8IahsAifJ/7kPMa0QOx7xP5IV8EnNrJpY0nbJaHkb5BkAFyk+cefV/2icZd
-p0AJPaxJRUXcLo0waLIJuvvDL8y6C98/d3tGfToSJI6WjzwFCm/SlCgdbQzALogi
-1djPHRPH8EjX1wWnz8dHnjs8NMiAT9QUu/wNUPf6s+xCX6ndbcj0dc97wXImsQEc
-XCz9ek60AcUFV7nnPKoF2YjpB0ZBzu9Bga5Y34OirsrXdx/nADydb47kMgkdTXg0
-eDQ8lJsm7U9xxhl6vSAiSFr+S30Dt+dYvsYyTnQeaN2oaFuzPu5ifdmA6Ap1erfu
-tGWaIZDgqtCYvDi1czyL+Nw=
------END CERTIFICATE-----
+# "Cisco Root CA 2048"
+# 83 27 BC 8C 9D 69 94 7B 3D E3 C2 75 11 53 72 67
+# F5 9C 21 B9 FA 7B 61 3F AF BC CD 53 B7 02 40 00
-----BEGIN CERTIFICATE-----
MIIDQzCCAiugAwIBAgIQX/h7KCtU3I1CoxW1aMmt/zANBgkqhkiG9w0BAQUFADA1
MRYwFAYDVQQKEw1DaXNjbyBTeXN0ZW1zMRswGQYDVQQDExJDaXNjbyBSb290IENB
@@ -995,6 +1279,9 @@ Bvt9YAretIpjsJyp8qS5UwGH0GikJ3+r/+n6yUA4iGe0OcaEb1fJU9u6ju7AQ7L4
CYNu/2bPPu8Xs1gYJQk0XuPL1hS27PKSb3TkL4Eq1ZKR4OCXPDJoBYVL0fdX4lId
kxpUnwVwwEpxYB5DC2Ae/qPOgRnhCzU=
-----END CERTIFICATE-----
+# "Class 2 Primary CA"
+# 0F 99 3C 8A EF 97 BA AF 56 87 14 0E D5 9A D1 82
+# 1B B4 AF AC F0 AA 9A 58 B5 D5 7A 33 8A 3A FB CB
-----BEGIN CERTIFICATE-----
MIIDkjCCAnqgAwIBAgIRAIW9S/PY2uNp9pTXX8OlRCMwDQYJKoZIhvcNAQEFBQAw
PTELMAkGA1UEBhMCRlIxETAPBgNVBAoTCENlcnRwbHVzMRswGQYDVQQDExJDbGFz
@@ -1017,28 +1304,9 @@ ybuJfm6AiB4vFLQDJKgybwOaRywwvlbGp0ICcBvqQNi6BQNwB6SW//1IMwrh3KWB
kJtN3X3n57LNXMhqlfil9o3EXXgIvnsG1knPGTZQIy4I5p4FTUcY1Rbpsda2ENW7
l7+ijrRU
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDoTCCAomgAwIBAgIQKTZHquOKrIZKI1byyrdhrzANBgkqhkiG9w0BAQUFADBO
-MQswCQYDVQQGEwJ1czEYMBYGA1UEChMPVS5TLiBHb3Zlcm5tZW50MQ0wCwYDVQQL
-EwRGQkNBMRYwFAYDVQQDEw1Db21tb24gUG9saWN5MB4XDTA3MTAxNTE1NTgwMFoX
-DTI3MTAxNTE2MDgwMFowTjELMAkGA1UEBhMCdXMxGDAWBgNVBAoTD1UuUy4gR292
-ZXJubWVudDENMAsGA1UECxMERkJDQTEWMBQGA1UEAxMNQ29tbW9uIFBvbGljeTCC
-ASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJeNvTMn5K1b+3i9L0dHbsd4
-6ZOcpN7JHP0vGzk4rEcXwH53KQA7Ax9oD81Npe53uCxiazH2+nIJfTApBnznfKM9
-hBiKHa4skqgf6F5PjY7rPxr4nApnnbBnTfAu0DDew5SwoM8uCjR/VAnTNr2kSVdS
-c+md/uRIeUYbW40y5KVIZPMiDZKdCBW/YDyD90ciJSKtKXG3d+8XyaK2lF7IMJCk
-FEhcVlcLQUwF1CpMP64Sm1kRdXAHImktLNMxzJJ+zM2kfpRHqpwJCPZLr1LoakCR
-xVW9QLHIbVeGlRfmH3O+Ry4+i0wXubklHKVSFzYIWcBCvgortFZRPBtVyYyQd+sC
-AwEAAaN7MHkwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0O
-BBYEFC9Yl9ipBZilVh/72at17wI8NjTHMBIGCSsGAQQBgjcVAQQFAgMBAAEwIwYJ
-KwYBBAGCNxUCBBYEFHa3YJbdFFYprHWF03BjwbxHhhyLMA0GCSqGSIb3DQEBBQUA
-A4IBAQBgrvNIFkBypgiIybxHLCRLXaCRc+1leJDwZ5B6pb8KrbYq+Zln34PFdx80
-CTj5fp5B4Ehg/uKqXYeI6oj9XEWyyWrafaStsU+/HA2fHprA1RRzOCuKeEBuMPdi
-4c2Z/FFpZ2wR3bgQo2jeJqVW/TZsN5hs++58PGxrcD/3SDcJjwtCga1GRrgLgwb0
-Gzigf0/NC++DiYeXHIowZ9z9VKEDfgHLhUyxCynDvux84T8PCVI8L6eaSP436REG
-WOE2QYrEtr+O3c5Ks7wawM36GpnScZv6z7zyxFSjiDV2zBssRm8MtNHDYXaSdBHq
-S4CNHIkRi+xb/xfJSPzn4AYR4oRe
------END CERTIFICATE-----
+# "COMODO Certification Authority"
+# 0C 2C D6 3D F7 80 6F A3 99 ED E8 09 11 6B 57 5B
+# F8 79 89 F0 65 18 F9 80 8C 86 05 03 17 8B AF 66
-----BEGIN CERTIFICATE-----
MIIEHTCCAwWgAwIBAgIQToEtioJl4AsC7j41AkblPTANBgkqhkiG9w0BAQUFADCB
gTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
@@ -1064,6 +1332,9 @@ zJVSk/BwJVmcIGfE7vmLV2H0knZ9P4SNVbfo5azV8fUZVqZa+5Acr5Pr5RzUZ5dd
BA6+C4OmF4O5MBKgxTMVBbkN+8cFduPYSo38NBejxiEovjBFMR7HeL5YYTisO+IB
ZQ==
-----END CERTIFICATE-----
+# "COMODO ECC Certification Authority"
+# 17 93 92 7A 06 14 54 97 89 AD CE 2F 8F 34 F7 F0
+# B6 6D 0F 3A E3 A3 B8 4D 21 EC 15 DB BA 4F AD C7
-----BEGIN CERTIFICATE-----
MIICiTCCAg+gAwIBAgIQH0evqmIAcFBUTAGem2OZKjAKBggqhkjOPQQDAzCBhTEL
MAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4GA1UE
@@ -1080,6 +1351,9 @@ BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjEA7wNbeqy3eApyt4jf/7VGFAkK+qDm
fQjGGoe9GKhzvSbKYAydzpmfz1wPMOG+FDHqAjAU9JM8SaczepBGR7NjfRObTrdv
GDeAU/7dIOA1mjbRxwG55tzd8/8dLDoWV9mSOdY=
-----END CERTIFICATE-----
+# "COMODO RSA Certification Authority"
+# 52 F0 E1 C4 E5 8E C6 29 29 1B 60 31 7F 07 46 71
+# B8 5D 7E A8 0D 5B 07 27 34 63 53 4B 32 B4 02 34
-----BEGIN CERTIFICATE-----
MIIF2DCCA8CgAwIBAgIQTKr5yttjb+Af907YWwOGnTANBgkqhkiG9w0BAQwFADCB
hTELMAkGA1UEBhMCR0IxGzAZBgNVBAgTEkdyZWF0ZXIgTWFuY2hlc3RlcjEQMA4G
@@ -1114,6 +1388,9 @@ QOhTsiedSrnAdyGN/4fy3ryM7xfft0kL0fJuMAsaDk527RH89elWsn2/x20Kk4yl
0MC2Hb46TpSi125sC8KKfPog88Tk5c0NqMuRkrF8hey1FGlmDoLnzc7ILaZRfyHB
NVOFBkpdn627G190
-----END CERTIFICATE-----
+# "ComSign CA"
+# AE 44 57 B4 0D 9E DA 96 67 7B 0D 3C 92 D5 7B 51
+# 77 AB D7 AC 10 37 95 83 56 D1 E0 94 51 8B E5 F2
-----BEGIN CERTIFICATE-----
MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0
MRMwEQYDVQQDEwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQG
@@ -1136,6 +1413,9 @@ hbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VGzT2ouvDzuFYk
Res3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U
AGegcQCCSA==
-----END CERTIFICATE-----
+# "ComSign Global Root CA"
+# 26 05 87 5A FC C1 76 B2 D6 6D D6 6A 99 5D 7F 8D
+# 5E BB 86 CE 12 0D 0E 7E 9E 7C 6E F2 94 A2 7D 4C
-----BEGIN CERTIFICATE-----
MIIGATCCA+mgAwIBAgIRAI9hcRW6eVgXjH0ROqzW264wDQYJKoZIhvcNAQELBQAw
RTEfMB0GA1UEAxMWQ29tU2lnbiBHbG9iYWwgUm9vdCBDQTEVMBMGA1UEChMMQ29t
@@ -1171,6 +1451,9 @@ Q0cYqWOY1LNjznRt9lweWEfwDBL3FhrHOmD4++1N3FkkM4W+Q1b2WOL24clDMj+i
VBYGFuMEUEQtybI+eIbnp5peO2WAAblQI4eTy/jMVowe5tfMEXovV3sz9ULgmGb3
DscLP1I=
-----END CERTIFICATE-----
+# "ComSign Secured CA"
+# 50 79 41 C7 44 60 A0 B4 70 86 22 0D 4E 99 32 57
+# 2A B5 D1 B5 BB CB 89 80 AB 1C B1 76 51 A8 44 D2
-----BEGIN CERTIFICATE-----
MIIDqzCCApOgAwIBAgIRAMcoRwmzuGxFjB36JPU2TukwDQYJKoZIhvcNAQEFBQAw
PDEbMBkGA1UEAxMSQ29tU2lnbiBTZWN1cmVkIENBMRAwDgYDVQQKEwdDb21TaWdu
@@ -1193,6 +1476,36 @@ kz/MdXSFmLr/YnpNH4n+rr2UAJm/EaXc4HnFFgt9AmEd6oX5AhVP51qJThRv4zdL
hfXBPGHg/QVBspJ/wx2g0K5SZGBrGMYmnNj1ZOQ2GmKfig8+/21OGVZOIJFsnzQz
OjRXUDpvgV4GxvU+fE6OK85lBi5d0ipTdF7Tbieejw==
-----END CERTIFICATE-----
+# "D-TRUST Root CA 3 2013"
+# A1 A8 6D 04 12 1E B8 7F 02 7C 66 F5 33 03 C2 8E
+# 57 39 F9 43 FC 84 B3 8A D6 AF 00 90 35 DD 94 57
+-----BEGIN CERTIFICATE-----
+MIIEDjCCAvagAwIBAgIDD92sMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNVBAYTAkRF
+MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxHzAdBgNVBAMMFkQtVFJVU1QgUm9vdCBD
+QSAzIDIwMTMwHhcNMTMwOTIwMDgyNTUxWhcNMjgwOTIwMDgyNTUxWjBFMQswCQYD
+VQQGEwJERTEVMBMGA1UECgwMRC1UcnVzdCBHbWJIMR8wHQYDVQQDDBZELVRSVVNU
+IFJvb3QgQ0EgMyAyMDEzMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+xHtCkoIf7O1UmI4SwMoJ35NuOpNcG+QQd55OaYhs9uFp8vabomGxvQcgdJhl8Ywm
+CM2oNcqANtFjbehEeoLDbF7eu+g20sRoNoyfMr2EIuDcwu4QRjltr5M5rofmw7wJ
+ySxrZ1vZm3Z1TAvgu8XXvD558l++0ZBX+a72Zl8xv9Ntj6e6SvMjZbu376Ml1wrq
+WLbviPr6ebJSWNXwrIyhUXQplapRO5AyA58ccnSQ3j3tYdLl4/1kR+W5t0qp9x+u
+loYErC/jpIF3t1oW/9gPP/a3eMykr/pbPBJbqFKJcu+I89VEgYaVI5973bzZNO98
+lDyqwEHC451QGsDkGSL8swIDAQABo4IBBTCCAQEwDwYDVR0TAQH/BAUwAwEB/zAd
+BgNVHQ4EFgQUP5DIfccVb/Mkj6nDL0uiDyGyL+cwDgYDVR0PAQH/BAQDAgEGMIG+
+BgNVHR8EgbYwgbMwdKByoHCGbmxkYXA6Ly9kaXJlY3RvcnkuZC10cnVzdC5uZXQv
+Q049RC1UUlVTVCUyMFJvb3QlMjBDQSUyMDMlMjAyMDEzLE89RC1UcnVzdCUyMEdt
+YkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRpb25saXN0MDugOaA3hjVodHRwOi8v
+Y3JsLmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2FfM18yMDEzLmNybDAN
+BgkqhkiG9w0BAQsFAAOCAQEADlkOWOR0SCNEzzQhtZwUGq2aS7eziG1cqRdw8Cqf
+jXv5e4X6xznoEAiwNStfzwLS05zICx7uBVSuN5MECX1sj8J0vPgclL4xAUAt8yQg
+t4RVLFzI9XRKEBmLo8ftNdYJSNMOwLo5qLBGArDbxohZwr78e7Erz35ih1WWzAFv
+m2chlTWL+BD8cRu3SzdppjvW7IvuwbDzJcmPkn2h6sPKRL8mpXSSnON065102ctN
+h9j8tGlsi6BDB2B4l+nZk3zCRrybN1Kj7Yo8E6l7U0tJmhEFLAtuVqwfLoJs4Gln
+tQ5tLdnkwBXxP/oYcuEVbSdbLTAoK59ImmQrme/ydUlfXA==
+-----END CERTIFICATE-----
+# "D-TRUST Root Class 3 CA 2 2009"
+# 49 E7 A4 42 AC F0 EA 62 87 05 00 54 B5 25 64 B6
+# 50 E4 F4 9E 42 E3 48 D6 AA 38 E0 39 E9 57 B1 C1
-----BEGIN CERTIFICATE-----
MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRF
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBD
@@ -1218,6 +1531,9 @@ zCUqNQT4YJEVdT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8
PIWmawomDeCTmGCufsYkl4phX5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3Y
Johw1+qRzT65ysCQblrGXnRl11z+o+I=
-----END CERTIFICATE-----
+# "D-TRUST Root Class 3 CA 2 EV 2009"
+# EE C5 49 6B 98 8C E9 86 25 B9 34 09 2E EC 29 08
+# BE D0 B0 F3 16 C2 D4 73 0C 84 EA F1 F3 D3 48 81
-----BEGIN CERTIFICATE-----
MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRF
MRUwEwYDVQQKDAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBD
@@ -1243,6 +1559,9 @@ CSuGdXzfX2lXANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7na
xpeG0ILD5EJt/rDiZE4OJudANCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqX
KVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVvw9y4AyHqnxbxLFS1
-----END CERTIFICATE-----
+# "Deutsche Telekom Root CA 2"
+# B6 19 1A 50 D0 C3 97 7F 7D A9 9B CD AA C8 6A 22
+# 7D AE B9 67 9E C7 0B A3 B0 C9 D9 22 71 C1 70 D3
-----BEGIN CERTIFICATE-----
MIIDnzCCAoegAwIBAgIBJjANBgkqhkiG9w0BAQUFADBxMQswCQYDVQQGEwJERTEc
MBoGA1UEChMTRGV1dHNjaGUgVGVsZWtvbSBBRzEfMB0GA1UECxMWVC1UZWxlU2Vj
@@ -1265,6 +1584,36 @@ IzpXl/V6ME+un2pMSyuOoAPjPuCp1NJ70rOo4nI8rZ7/gFnkm0W09juwzTkZmDLl
xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU
Cm26OWMohpLzGITY+9HPBVZkVw==
-----END CERTIFICATE-----
+# "Developer ID Certification Authority"
+# 7A FC 9D 01 A6 2F 03 A2 DE 96 37 93 6D 4A FE 68
+# 09 0D 2D E1 8D 03 F2 9C 88 CF B0 B1 BA 63 58 7F
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIIGHqpqMKWIQwwDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkFwcGxlIEluYy4xJjAkBgNVBAsTHUFwcGxlIENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MRYwFAYDVQQDEw1BcHBsZSBSb290IENBMB4XDTEy
+MDIwMTIyMTIxNVoXDTI3MDIwMTIyMTIxNVoweTEtMCsGA1UEAwwkRGV2ZWxvcGVy
+IElEIENlcnRpZmljYXRpb24gQXV0aG9yaXR5MSYwJAYDVQQLDB1BcHBsZSBDZXJ0
+aWZpY2F0aW9uIEF1dGhvcml0eTETMBEGA1UECgwKQXBwbGUgSW5jLjELMAkGA1UE
+BhMCVVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCJdk8GW5pB7qUj
+KwKjX9dzP8A1sIuECj8GJH+nlT/rTw6Tr7QO0Mg+5W0Ysx/oiUe/1wkI5P9WmCkV
+55SduTWjCs20wOHiYPTK7Cl4RWlpYGtfipL8niPmOsIiszFPHLrytjRZQu6wqQID
+GJEEtrN4LjMfgEUNRW+7Dlpbfzrn2AjXCw4ybfuGNuRsq8QRinCEJqqfRNHxuMZ7
+lBebSPcLWBa6I8WfFTl+yl3DMl8P4FJ/QOq+rAhklVvJGpzlgMofakQcbD7EsCYf
+Hex7r16gaj1HqVgSMT8gdihtHRywwk4RaSaLy9bQEYLJTg/xVnTQ2QhLZniiq6yn
+4tJMh1nJAgMBAAGjgaYwgaMwHQYDVR0OBBYEFFcX7aLP3HyYoRDg/L6HLSzy4xdU
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUK9BpR5R2Cf70a40uQKb3R01/
+CF4wLgYDVR0fBCcwJTAjoCGgH4YdaHR0cDovL2NybC5hcHBsZS5jb20vcm9vdC5j
+cmwwDgYDVR0PAQH/BAQDAgGGMBAGCiqGSIb3Y2QGAgYEAgUAMA0GCSqGSIb3DQEB
+CwUAA4IBAQBCOXRrodzGpI83KoyzHQpEvJUsf7xZuKxh+weQkjK51L87wVA5akR0
+ouxbH3Dlqt1LbBwjcS1f0cWTvu6binBlgp0W4xoQF4ktqM39DHhYSQwofzPuAHob
+tHastrW7T9+oG53IGZdKC1ZnL8I+trPEgzrwd210xC4jUe6apQNvYPSlSKcGwrta
+4h8fRkV+5Jf1JxC3ICJyb3LaxlB1xT0lj12jAOmfNoxIOY+zO+qQgC6VmmD0eM70
+DgpTPqL6T9geroSVjTK8Vk2J6XgY4KyaQrp6RhuEoonOFOiI0ViL9q5WxCwFKkWv
+C9lLqQIPNKyIx2FViUTJJ3MH7oLlTvVw
+-----END CERTIFICATE-----
+# "DigiCert Assured ID Root CA"
+# 3E 90 99 B5 01 5E 8F 48 6C 00 BC EA 9D 11 1E E7
+# 21 FA BA 35 5A 89 BC F1 DF 69 56 1E 3D C6 32 5C
-----BEGIN CERTIFICATE-----
MIIDtzCCAp+gAwIBAgIQDOfg5RfYRv6P5WD8G/AwOTANBgkqhkiG9w0BAQUFADBl
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1287,6 +1636,9 @@ NW1fiQG2SVufAQWbqz0lwcy2f8Lxb4bG+mRo64EtlOtCt/qMHt1i8b5QZ7dsvfPx
H2sMNgcWfzd8qVttevESRmCD1ycEvkvOl77DZypoEd+A5wwzZr8TDRRu838fYxAe
+o0bJW1sj6W3YQGx0qMmoRBxna3iw/nDmVG3KwcIzi7mULKn+gpFL6Lw8g==
-----END CERTIFICATE-----
+# "DigiCert Assured ID Root G2"
+# 7D 05 EB B6 82 33 9F 8C 94 51 EE 09 4E EB FE FA
+# 79 53 A1 14 ED B2 F4 49 49 45 2F AB 7D 2F C1 85
-----BEGIN CERTIFICATE-----
MIIDljCCAn6gAwIBAgIQC5McOtY5Z+pnI7/Dr5r0SzANBgkqhkiG9w0BAQsFADBl
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1309,6 +1661,9 @@ B5yiutkBclzzTcHdDrEcDcRjvq30FPuJ7KJBDkzMyFdA0G4Dqs0MjomZmWzwPDCv
ON9vvKO+KSAnq3T/EyJ43pdSVR6DtVQgA+6uwE9W3jfMw3+qBCe703e4YtsXfJwo
IhNzbM8m9Yop5w==
-----END CERTIFICATE-----
+# "DigiCert Assured ID Root G3"
+# 7E 37 CB 8B 4C 47 09 0C AB 36 55 1B A6 F4 5D B8
+# 40 68 0F BA 16 6A 95 2D B1 00 71 7F 43 05 3F C2
-----BEGIN CERTIFICATE-----
MIICRjCCAc2gAwIBAgIQC6Fa+h3foLVJRK/NJKBs7DAKBggqhkjOPQQDAzBlMQsw
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
@@ -1324,6 +1679,9 @@ AwNnADBkAjAlpIFFAmsSS3V0T8gj43DydXLefInwz5FyYZ5eEJJZVrmDxxDnOOlY
JjZ91eQ0hjkCMHw2U/Aw5WJjOpnitqM7mzT6HtoQknFekROn3aRukswy1vUhZscv
6pZjamVFkpUBtA==
-----END CERTIFICATE-----
+# "DigiCert Global Root CA"
+# 43 48 A0 E9 44 4C 78 CB 26 5E 05 8D 5E 89 44 B4
+# D8 4F 96 62 BD 26 DB 25 7F 89 34 A4 43 C7 01 61
-----BEGIN CERTIFICATE-----
MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1346,6 +1704,9 @@ PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
-----END CERTIFICATE-----
+# "DigiCert Global Root G2"
+# CB 3C CB B7 60 31 E5 E0 13 8F 8D D3 9A 23 F9 DE
+# 47 FF C3 5E 43 C1 14 4C EA 27 D4 6A 5A B1 CB 5F
-----BEGIN CERTIFICATE-----
MIIDjjCCAnagAwIBAgIQAzrx5qcRqaC7KGSxHQn65TANBgkqhkiG9w0BAQsFADBh
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1368,6 +1729,9 @@ Fdtom/DzMNU+MeKNhJ7jitralj41E6Vf8PlwUHBHQRFXGU7Aj64GxJUTFy8bJZ91
pLiaWN0bfVKfjllDiIGknibVb63dDcY3fe0Dkhvld1927jyNxF1WW6LZZm6zNTfl
MrY=
-----END CERTIFICATE-----
+# "DigiCert Global Root G3"
+# 31 AD 66 48 F8 10 41 38 C7 38 F3 9E A4 32 01 33
+# 39 3E 3A 18 CC 02 29 6E F9 7C 2A C9 EF 67 31 D0
-----BEGIN CERTIFICATE-----
MIICPzCCAcWgAwIBAgIQBVVWvPJepDU1w6QP1atFcjAKBggqhkjOPQQDAzBhMQsw
CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu
@@ -1383,6 +1747,9 @@ AK288mw/EkrRLTnDCgmXc/SINoyIJ7vmiI1Qhadj+Z4y3maTD/HMsQmP3Wyr+mt/
oAIwOWZbwmSNuJ5Q3KjVSaLtx9zRSX8XAbjIho9OjIgrqJqpisXRAL34VOKa5Vt8
sycX
-----END CERTIFICATE-----
+# "DigiCert High Assurance EV Root CA"
+# 74 31 E5 F4 C3 C1 CE 46 90 77 4F 0B 61 E0 54 40
+# 88 3B A9 A0 1E D0 0B A6 AB D7 80 6E D3 B1 18 CF
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIQAqxcJmoLQJuPC3nyrkYldzANBgkqhkiG9w0BAQUFADBs
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1406,6 +1773,9 @@ Yzi9RKR/5CYrCsSXaQ3pjOLAEFe4yHYSkVXySGnYvCoCWw9E1CAx2/S6cCZdkGCe
vEsXCS+0yx5DaMkHJ8HSXPfqIbloEpw8nL+e/IBcm2PN7EeqJSdnoDfzAIJ9VNep
+OkuE6N36B9K
-----END CERTIFICATE-----
+# "DigiCert Trusted Root G4"
+# 55 2F 7B DC F1 A7 AF 9E 6C E6 72 01 7F 4F 12 AB
+# F7 72 40 C7 8E 76 1A C2 03 D1 D9 D2 0A C8 99 88
-----BEGIN CERTIFICATE-----
MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
@@ -1438,30 +1808,9 @@ r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1
/YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm
gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIECTCCAvGgAwIBAgIQDV6ZCtadt3js2AdWO4YV2TANBgkqhkiG9w0BAQUFADBb
-MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3Qx
-ETAPBgNVBAsTCERTVCBBQ0VTMRcwFQYDVQQDEw5EU1QgQUNFUyBDQSBYNjAeFw0w
-MzExMjAyMTE5NThaFw0xNzExMjAyMTE5NThaMFsxCzAJBgNVBAYTAlVTMSAwHgYD
-VQQKExdEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdDERMA8GA1UECxMIRFNUIEFDRVMx
-FzAVBgNVBAMTDkRTVCBBQ0VTIENBIFg2MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
-MIIBCgKCAQEAuT31LMmU3HWKlV1j6IR3dma5WZFcRt2SPp/5DgO0PWGSvSMmtWPu
-ktKe1jzIDZBfZIGxqAgNTNj50wUoUrQBJcWVHAx+PhCEdc/BGZFjz+iokYi5Q1K7
-gLFViYsx+tC3dr5BPTCapCIlF3PoHuLTrCq9Wzgh1SpL11V94zpVvddtawJXa+ZH
-fAjIgrrep4c9oW24MFbCswKBXy314powGCi4ZtPLAZZv6opFVdbgnf9nKxcCpk4a
-ahELfrd755jWjHZvwTvbUJN+5dCOHze4vbrGn2zpfDPyMjwmR/onJALJfh1biEIT
-ajV8fTXpLmaRcpPVMibEdPVTo7NdmvYJywIDAQABo4HIMIHFMA8GA1UdEwEB/wQF
-MAMBAf8wDgYDVR0PAQH/BAQDAgHGMB8GA1UdEQQYMBaBFHBraS1vcHNAdHJ1c3Rk
-c3QuY29tMGIGA1UdIARbMFkwVwYKYIZIAWUDAgEBATBJMEcGCCsGAQUFBwIBFjto
-dHRwOi8vd3d3LnRydXN0ZHN0LmNvbS9jZXJ0aWZpY2F0ZXMvcG9saWN5L0FDRVMt
-aW5kZXguaHRtbDAdBgNVHQ4EFgQUCXIGThhDD+XWzMNqizF7eI+og7gwDQYJKoZI
-hvcNAQEFBQADggEBAKPYjtay284F5zLNAdMEA+V25FYrnJmQ6AgwbN99Pe7lv7Uk
-QIRJ4dEorsTCOlMwiPH1d25Ryvr/ma8kXxug/fKshMrfqfBfBC6tFr8hlxCBPeP/
-h40y3JTlR4peahPJlJU90u7INJXQgNStMgiAVDzgvVJT11J8smk/f3rPanTK+gQq
-nExaBqXpIK1FZg9p8d2/6eMyi/rgwYZNcjwu2JN4Cir42NInPRmJX1p7ijvMDNpR
-rscL9yuwNwXsvFcj4jjSm2jzVhKIT0J8uDHEtdvkyCE06UgRNe76x5JXxZ805Mf2
-9w4LTJxoeHtxMcfrHuBnQfO3oKfN5XozNmr6mis=
------END CERTIFICATE-----
+# "DST Root CA X3"
+# 06 87 26 03 31 A7 24 03 D9 09 F1 05 E6 9B CF 0D
+# 32 E1 BD 24 93 FF C6 D9 20 6D 11 BC D6 77 07 39
-----BEGIN CERTIFICATE-----
MIIDSjCCAjKgAwIBAgIQRK+wgNajJ7qJMDmGLvhAazANBgkqhkiG9w0BAQUFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
@@ -1482,6 +1831,9 @@ R8srzJmwN0jP41ZL9c8PDHIyh8bwRLtTcm1D9SZImlJnt1ir/md2cXjbDaJWFBM5
JDGFoqgCWjBH4d1QB7wCCZAA62RjYJsWvIjJEubSfZGL+T0yjWW06XyxV3bqxbYo
Ob8VZRzI9neWagqNdwvYkQsEjgfbKbYK7p2CNTUQ
-----END CERTIFICATE-----
+# "DST Root CA X4"
+# 9A 73 92 9A 50 0F 1A 0B F4 9D CB 04 6E 80 39 16
+# 96 96 55 73 45 E9 F8 13 F1 0F F9 38 0D B2 26 95
-----BEGIN CERTIFICATE-----
MIIDOzCCAiOgAwIBAgIRANAeRlAAACmMAAAAAgAAAAIwDQYJKoZIhvcNAQEFBQAw
PzEkMCIGA1UEChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMRcwFQYDVQQD
@@ -1502,6 +1854,9 @@ mf12VJffL6W8omBPtgteb6UaT/k1oJ7YI0ldGf+ngpVbRhD+LC3cUtT6GO/BEPZu
8YTV/hbiDH5v3khVqMIeKT6o8IuXGG7F6a6vKwP1F1FwTXf4UC/ivhme7vdUH7B/
Vv4AEbT8dNfEeFxrkDbh
-----END CERTIFICATE-----
+# "E-Tugra Certification Authority"
+# B0 BF D5 2B B0 D7 D9 BD 92 BF 5D 4D C1 3D A2 55
+# C0 2C 54 2F 37 83 65 EA 89 39 11 F5 5E 55 F2 3C
-----BEGIN CERTIFICATE-----
MIIGSzCCBDOgAwIBAgIIamg+nFGby1MwDQYJKoZIhvcNAQELBQAwgbIxCzAJBgNV
BAYTAlRSMQ8wDQYDVQQHDAZBbmthcmExQDA+BgNVBAoMN0UtVHXEn3JhIEVCRyBC
@@ -1538,6 +1893,9 @@ AJ8C2sH6H3p6CcRK5ogql5+Ji/03X186zjhZhkuvcQu02PJwT58yE+Owp1fl2tpD
y4Q08ijE6m30Ku/Ba3ba+367hTzSU8JNvnHhRdH9I2cNE3X7z2VnIp2usAnRCf8d
NL/+I5c30jn6PQ0GC7TbO6Orb1wdtn7os4I07QZcJA==
-----END CERTIFICATE-----
+# "Echoworx Root CA2"
+# 66 39 D1 3C AB 85 DF 1A D9 A2 3C 44 3B 3A 60 90
+# 1E 2B 13 8D 45 6F A7 11 83 57 81 08 88 4E C6 BF
-----BEGIN CERTIFICATE-----
MIIE5zCCA8+gAwIBAgIBADANBgkqhkiG9w0BAQUFADCBjTELMAkGA1UEBhMCQ0Ex
EDAOBgNVBAgTB09udGFyaW8xEDAOBgNVBAcTB1Rvcm9udG8xHTAbBgNVBAoTFEVj
@@ -1567,6 +1925,9 @@ QpDL9G+16F7GkmnKlAIYT3QTS3yFGYChnJcd+6txUPhKi9sSOOmAIaKHnkH9Scz+
A2cSi4A3wUYXVatuVNHpRb2lygfH3SuCX9MU8Ure3zBlSU1LALtMqI4JmcQmQpIq
zIzvO2jHyu9PQqo=
-----END CERTIFICATE-----
+# "EE Certification Centre Root CA"
+# 3E 84 BA 43 42 90 85 16 E7 75 73 C0 99 2F 09 79
+# CA 08 4E 46 85 68 1F F1 95 CC BA 8A 22 9B 8A 76
-----BEGIN CERTIFICATE-----
MIIEAzCCAuugAwIBAgIQVID5oHPtPwBMyonY43HmSjANBgkqhkiG9w0BAQUFADB1
MQswCQYDVQQGEwJFRTEiMCAGA1UECgwZQVMgU2VydGlmaXRzZWVyaW1pc2tlc2t1
@@ -1591,6 +1952,39 @@ uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIW
iAYLtqZLICjU3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/v
GVCJYMzpJJUPwssd8m92kMfMdcGWxZ0=
-----END CERTIFICATE-----
+# "Entrust Root Certification Authority"
+# 73 C1 76 43 4F 1B C6 D5 AD F4 5B 0E 76 E7 27 28
+# 7C 8D E5 76 16 C1 E6 E6 14 1A 2B 2C BC 7D 8E 4C
+-----BEGIN CERTIFICATE-----
+MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
+VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
+Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
+KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
+cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
+NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
+NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
+ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
+BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
+KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
+Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
+4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
+KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
+rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
+94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
+sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
+gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
+kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
+vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
+A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
+O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
+AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
+9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
+eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
+0vdXcDazv/wor3ElhVsT/h5/WrQ8
+-----END CERTIFICATE-----
+# "Entrust Root Certification Authority - EC1"
+# 02 ED 0E B2 8C 14 DA 45 16 5C 56 67 91 70 0D 64
+# 51 D7 FB 56 F0 B2 AB 1D 3B 8E B0 70 E5 6E DF F5
-----BEGIN CERTIFICATE-----
MIIC+TCCAoCgAwIBAgINAKaLeSkAAAAAUNCR+TAKBggqhkjOPQQDAzCBvzELMAkG
A1UEBhMCVVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3
@@ -1609,6 +2003,9 @@ BBYEFLdj5xrdjekIplWDpOBqUEFlEUJJMAoGCCqGSM49BAMDA2cAMGQCMGF52OVC
R98crlOZF7ZvHH3hvxGU0QOIdeSNiaSKd0bebWHvAvX7td/M/k7//qnmpwIwW5nX
hTcGtXsI/esni0qU+eH6p44mCOh8kmhtc9hvJqwhAriZtyZBWyVgrtBIGu4G
-----END CERTIFICATE-----
+# "Entrust Root Certification Authority - G2"
+# 43 DF 57 74 B0 3E 7F EF 5F E4 0D 93 1A 7B ED F1
+# BB 2E 6B 42 73 8C 4E 6D 38 41 10 3D 3A A7 F3 39
-----BEGIN CERTIFICATE-----
MIIEPjCCAyagAwIBAgIESlOMKDANBgkqhkiG9w0BAQsFADCBvjELMAkGA1UEBhMC
VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xKDAmBgNVBAsTH1NlZSB3d3cuZW50
@@ -1634,33 +2031,9 @@ Rkfz6/djwUAFQKXSt/S1mja/qYh2iARVBCuch38aNzx+LaUa2NSJXsq9rD1s2G2v
nAuknZoh8/CbCzB428Hch0P+vGOaysXCHMnHjf87ElgI5rY97HosTvuDls4MPGmH
VHOkc8KT/1EQrBVUAdj8BbGJoX90g5pJ19xOe4pIb4tF9g==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEkTCCA3mgAwIBAgIERWtQVDANBgkqhkiG9w0BAQUFADCBsDELMAkGA1UEBhMC
-VVMxFjAUBgNVBAoTDUVudHJ1c3QsIEluYy4xOTA3BgNVBAsTMHd3dy5lbnRydXN0
-Lm5ldC9DUFMgaXMgaW5jb3Jwb3JhdGVkIGJ5IHJlZmVyZW5jZTEfMB0GA1UECxMW
-KGMpIDIwMDYgRW50cnVzdCwgSW5jLjEtMCsGA1UEAxMkRW50cnVzdCBSb290IENl
-cnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTA2MTEyNzIwMjM0MloXDTI2MTEyNzIw
-NTM0MlowgbAxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1FbnRydXN0LCBJbmMuMTkw
-NwYDVQQLEzB3d3cuZW50cnVzdC5uZXQvQ1BTIGlzIGluY29ycG9yYXRlZCBieSBy
-ZWZlcmVuY2UxHzAdBgNVBAsTFihjKSAyMDA2IEVudHJ1c3QsIEluYy4xLTArBgNV
-BAMTJEVudHJ1c3QgUm9vdCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTCCASIwDQYJ
-KoZIhvcNAQEBBQADggEPADCCAQoCggEBALaVtkNC+sZtKm9I35RMOVcF7sN5EUFo
-Nu3s/poBj6E4KPz3EEZmLk0eGrEaTsbRwJWIsMn/MYszA9u3g3s+IIRe7bJWKKf4
-4LlAcTfFy0cOlypowCKVYhXbR9n10Cv/gkvJrT7eTNuQgFA/CYqEAOwwCj0Yzfv9
-KlmaI5UXLEWeH25DeW0MXJj+SKfFI0dcXv1u5x609mhF0YaDW6KKjbHjKYD+JXGI
-rb68j6xSlkuqUY3kEzEZ6E5Nn9uss2rVvDlUccp6en+Q3X0dgNmBu1kmwhH+5pPi
-94DkZfs0Nw4pgHBNrziGLp5/V6+eF67rHMsoIV+2HNjnogQi+dPa2MsCAwEAAaOB
-sDCBrTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zArBgNVHRAEJDAi
-gA8yMDA2MTEyNzIwMjM0MlqBDzIwMjYxMTI3MjA1MzQyWjAfBgNVHSMEGDAWgBRo
-kORnpKZTgMeGZqTx90tD+4S9bTAdBgNVHQ4EFgQUaJDkZ6SmU4DHhmak8fdLQ/uE
-vW0wHQYJKoZIhvZ9B0EABBAwDhsIVjcuMTo0LjADAgSQMA0GCSqGSIb3DQEBBQUA
-A4IBAQCT1DCw1wMgKtD5Y+iRDAUgqV8ZyntyTtSx29CW+1RaGSwMCPeyvIWonX9t
-O1KzKtvn1ISMY/YPyyYBkVBs9F8U4pN0wBOeMDpQ47RgxRzwIkSNcUesyBrJ6Zua
-AGAT/3B+XxFNSRuzFVJ7yVTav52Vr2ua2J7p8eRDjeIRRDq/r72DQnNSi6q7pynP
-9WQcCk3RvKqsnyrQ/39/2n3qse0wJcGE2jTSW3iDVuycNsMm4hH2Z0kdkquM++v/
-eu6FSqdQgPCnXEqULl8FmTxSQeDNtGPPAUO6nIPcj2A781q0tHuu2guQOHXvgR1m
-0vdXcDazv/wor3ElhVsT/h5/WrQ8
------END CERTIFICATE-----
+# "Entrust.net Certification Authority (2048)"
+# D1 C3 39 EA 27 84 EB 87 0F 93 4F C5 63 4E 4A A9
+# AD 55 05 01 64 01 F2 64 65 D3 7A 57 46 63 35 9F
-----BEGIN CERTIFICATE-----
MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
@@ -1687,6 +2060,9 @@ f3v/rxzP5tsHrV7bhZ3QKw0z2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfN
B/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjXOP/swNlQ8C5LWK5Gb9Auw2DaclVy
vUxFnmG6v4SBkgPR0ml8xQ==
-----END CERTIFICATE-----
+# "Entrust.net Certification Authority (2048)"
+# 6D C4 71 72 E0 1C BC B0 BF 62 58 0D 89 5F E2 B8
+# AC 9A D4 F8 73 80 1E 0C 10 B9 C8 37 D2 1E B1 77
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChML
RW50cnVzdC5uZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBp
@@ -1712,6 +2088,9 @@ u/8j72gZyxKTJ1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+
bYQLCIt+jerXmCHG8+c8eS9enNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/Er
fF6adulZkMV8gzURZVE=
-----END CERTIFICATE-----
+# "ePKI Root Certification Authority"
+# C0 A6 F4 DC 63 A2 4B FD CF 54 EF 2A 6A 08 2A 0A
+# 72 DE 35 80 3E 2F F5 FF 52 7A E5 D8 72 06 DF D5
-----BEGIN CERTIFICATE-----
MIIFsDCCA5igAwIBAgIQFci9ZUdcr7iXAF7kBtK8nTANBgkqhkiG9w0BAQUFADBe
MQswCQYDVQQGEwJUVzEjMCEGA1UECgwaQ2h1bmdod2EgVGVsZWNvbSBDby4sIEx0
@@ -1745,32 +2124,44 @@ Gp1iro2C6pSe3VkQw63d4k3jMdXH7OjysP6SHhYKGvzZ8/gntsm+HbRsZJB/9OTE
W9c3rkIO3aQab3yIVMUWbuF6aC74Or8NpDyJO3inTmODBCEIZ43ygknQW/2xzQ+D
hNQ+IIX3Sj0rnP0qCglN6oH4EZw=
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEYDCCA0igAwIBAgICATAwDQYJKoZIhvcNAQELBQAwWTELMAkGA1UEBhMCVVMx
-GDAWBgNVBAoTD1UuUy4gR292ZXJubWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UE
-AxMYRmVkZXJhbCBDb21tb24gUG9saWN5IENBMB4XDTEwMTIwMTE2NDUyN1oXDTMw
-MTIwMTE2NDUyN1owWTELMAkGA1UEBhMCVVMxGDAWBgNVBAoTD1UuUy4gR292ZXJu
-bWVudDENMAsGA1UECxMERlBLSTEhMB8GA1UEAxMYRmVkZXJhbCBDb21tb24gUG9s
-aWN5IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HX7NRY0WkG/
-Wq9cMAQUHK14RLXqJup1YcfNNnn4fNi9KVFmWSHjeavUeL6wLbCh1bI1FiPQzB6+
-Duir3MPJ1hLXp3JoGDG4FyKyPn66CG3G/dFYLGmgA/Aqo/Y/ISU937cyxY4nsyOl
-4FKzXZbpsLjFxZ+7xaBugkC7xScFNknWJidpDDSPzyd6KgqjQV+NHQOGgxXgVcHF
-mCye7Bpy3EjBPvmE0oSCwRvDdDa3ucc2Mnr4MrbQNq4iGDGMUHMhnv6DOzCIJOPp
-wX7e7ZjHH5IQip9bYi+dpLzVhW86/clTpyBLqtsgqyFOHQ1O5piF5asRR12dP8Qj
-wOMUBm7+nQIDAQABo4IBMDCCASwwDwYDVR0TAQH/BAUwAwEB/zCB6QYIKwYBBQUH
-AQsEgdwwgdkwPwYIKwYBBQUHMAWGM2h0dHA6Ly9odHRwLmZwa2kuZ292L2ZjcGNh
-L2NhQ2VydHNJc3N1ZWRCeWZjcGNhLnA3YzCBlQYIKwYBBQUHMAWGgYhsZGFwOi8v
-bGRhcC5mcGtpLmdvdi9jbj1GZWRlcmFsJTIwQ29tbW9uJTIwUG9saWN5JTIwQ0Es
-b3U9RlBLSSxvPVUuUy4lMjBHb3Zlcm5tZW50LGM9VVM/Y0FDZXJ0aWZpY2F0ZTti
-aW5hcnksY3Jvc3NDZXJ0aWZpY2F0ZVBhaXI7YmluYXJ5MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQUrQx6dVzl85jEeZgOrCj9l/TnAvwwDQYJKoZIhvcNAQELBQAD
-ggEBAI9z2uF/gLGH9uwsz9GEYx728Yi3mvIRte9UrYpuGDco71wb5O9Qt2wmGCMi
-TR0mRyDpCZzicGJxqxHPkYnos/UqoEfAFMtOQsHdDA4b8Idb7OV316rgVNdF9IU+
-7LQd3nyKf1tNnJaK0KIyn9psMQz4pO9+c+iR3Ah6cFqgr2KBWfgAdKLI3VTKQVZH
-venAT+0g3eOlCd+uKML80cgX2BLHb94u6b2akfI8WpQukSKAiaGMWMyDeiYZdQKl
-Dn0KJnNR6obLB6jI/WNaNZvSr79PMUjBhHDbNXuaGQ/lj/RqDG8z2esccKIN47lQ
-A2EC/0rskqTcLe4qNJMHtyznGI8=
------END CERTIFICATE-----
+# "GDCA TrustAUTH R5 ROOT"
+# BF FF 8F D0 44 33 48 7D 6A 8A A6 0C 1A 29 76 7A
+# 9F C2 BB B0 5E 42 0F 71 3A 13 B9 92 89 1D 38 93
+-----BEGIN CERTIFICATE-----
+MIIFiDCCA3CgAwIBAgIIfQmX/vBH6nowDQYJKoZIhvcNAQELBQAwYjELMAkGA1UE
+BhMCQ04xMjAwBgNVBAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZ
+IENPLixMVEQuMR8wHQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMB4XDTE0
+MTEyNjA1MTMxNVoXDTQwMTIzMTE1NTk1OVowYjELMAkGA1UEBhMCQ04xMjAwBgNV
+BAoMKUdVQU5HIERPTkcgQ0VSVElGSUNBVEUgQVVUSE9SSVRZIENPLixMVEQuMR8w
+HQYDVQQDDBZHRENBIFRydXN0QVVUSCBSNSBST09UMIICIjANBgkqhkiG9w0BAQEF
+AAOCAg8AMIICCgKCAgEA2aMW8Mh0dHeb7zMNOwZ+Vfy1YI92hhJCfVZmPoiC7XJj
+Dp6L3TQsAlFRwxn9WVSEyfFrs0yw6ehGXTjGoqcuEVe6ghWinI9tsJlKCvLriXBj
+TnnEt1u9ol2x8kECK62pOqPseQrsXzrj/e+APK00mxqriCZ7VqKChh/rNYmDf1+u
+KU49tm7srsHwJ5uu4/Ts765/94Y9cnrrpftZTqfrlYwiOXnhLQiPzLyRuEH3FMEj
+qcOtmkVEs7LXLM3GKeJQEK5cy4KOFxg2fZfmiJqwTTQJ9Cy5WmYqsBebnh52nUpm
+MUHfP/vFBu8btn4aRjb3ZGM74zkYI+dndRTVdVeSN72+ahsmUPI2JgaQxXABZG12
+ZuGR224HwGGALrIuL4xwp9E7PLOR5G62xDtw8mySlwnNR30YwPO7ng/Wi64HtloP
+zgsMR6flPri9fcebNaBhlzpBdRfMK5Z3KpIhHtmVdiBnaM8Nvd/WHwlqmuLMc3Gk
+L30SgLdTMEZeS1SZD2fJpcjyIMGC7J0R38IC+xo70e0gmu9lZJIQDSri3nDxGGeC
+jGHeuLzRL5z7D9Ar7Rt2ueQ5Vfj4oR24qoAATILnsn8JuLwwoC8N9VKejveSswoA
+HQBUlwbgsQfZxw9cZX08bVlX5O2ljelAU58VS6Bx9hoh49pwBiFYFIeFd3mqgnkC
+AwEAAaNCMEAwHQYDVR0OBBYEFOLJQJ9NzuiaoXzPDj9lxSmIahlRMA8GA1UdEwEB
+/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQDRSVfg
+p8xoWLoBDysZzY2wYUWsEe1jUGn4H3++Fo/9nesLqjJHdtJnJO29fDMylyrHBYZm
+DRd9FBUb1Ov9H5r2XpdptxolpAqzkT9fNqyL7FeoPueBihhXOYV0GkLH6VsTX4/5
+COmSdI31R9KrO9b7eGZONn356ZLpBN79SWP8bfsUcZNnL0dKt7n/HipzcEYwv1ry
+L3ml4Y0M2fmyYzeMN2WFcGpcWwlyua1jPLHd+PwyvzeG5LuOmCd+uh8W4XAR8gPf
+JWIyJyYYMoSf/wA6E7qaTfRPuBRwIrHKK5DOKcFw9C+df/KQHtZa37dG/OaG+svg
+IHZ6uqbL9XzeYqWxi+7egmaKTjowHz+Ay60nugxe19CxVsp3cbK1daFQqUBDF8Io
+2c9Si1vIY9RCPqAzekYu9wogRlR+ak8x8YF+QnQ4ZXMn7sZ8uI7XpTrXmKGcjBBV
+09tL7ECQ8s1uV9JiDnxXk7Gnbc2dg7sq5+W2O3FYrf3RRbxake5TFW/TRQl1brqQ
+XR4EzzffHqhmsYzmIGrv/EhOdJhCrylvLmrH+33RZjEizIYAfmaDDEL0vTSSwxrq
+T8p+ck0LcIymSLumoRT2+1hEmRSuqguTaaApJUqlyyvdimYHFngVV3Eb7PVHhPOe
+MTd61X8kreS8/f3MboPoDKi3QWwH3b08hpcv0g==
+-----END CERTIFICATE-----
+# "GeoTrust Global CA"
+# FF 85 6A 2D 25 1D CD 88 D3 66 56 F4 50 12 67 98
+# CF AB AA DE 40 79 9C 72 2D E4 D2 B5 DB 36 A7 3A
-----BEGIN CERTIFICATE-----
MIIDVDCCAjygAwIBAgIDAjRWMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
@@ -1791,6 +2182,33 @@ PseKUgzbFbS9bZvlxrFUaKnjaZC2mqUPuLk/IH2uSrW4nOQdtqvmlKXBx4Ot2/Un
hw4EbNX/3aBd7YdStysVAq45pmp06drE57xNNB6pXE0zX5IJL4hmXXeXxx12E6nV
5fEWCRE11azbJHFwLJhWC9kXtNHjUStedejV0NxPNO3CBWaAocvmMw==
-----END CERTIFICATE-----
+# "GeoTrust Primary Certification Authority"
+# 37 D5 10 06 C5 12 EA AB 62 64 21 F1 EC 8C 92 01
+# 3F C5 F8 2A E9 8E E5 33 EB 46 19 B8 DE B4 D0 6C
+-----BEGIN CERTIFICATE-----
+MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
+MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
+R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
+MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
+Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
+ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
+AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
+AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
+ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
+7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
+kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
+mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
+A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
+KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
+6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
+4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
+oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
+UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
+AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+-----END CERTIFICATE-----
+# "GeoTrust Primary Certification Authority - G2"
+# 5E DB 7A C4 3B 82 A0 6A 87 61 E8 D7 BE 49 79 EB
+# F2 61 1F 7D D7 9B F9 1C 1C 6B 56 6A 21 9E D7 66
-----BEGIN CERTIFICATE-----
MIICrjCCAjWgAwIBAgIQPLL0SAoA4v7rJDteYD7DazAKBggqhkjOPQQDAzCBmDEL
MAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsTMChj
@@ -1808,6 +2226,9 @@ CCqGSM49BAMDA2cAMGQCMGSWWaboCd6LuvpaiIjwH5HTRqjySkwCY/tsXzjbLkGT
qQ7mndwxHLKgpxgceeHHNgIwOlavmnRs9vuD4DPTCF+hnMJbn0bWtsuRBmOiBucz
rD6ogRLQy7rQkgu2npaqBA+K
-----END CERTIFICATE-----
+# "GeoTrust Primary Certification Authority - G3"
+# B4 78 B8 12 25 0D F8 78 63 5C 2A A7 EC 7D 15 5E
+# AA 62 5E E8 29 16 E2 CD 29 43 61 88 6C D1 FB D4
-----BEGIN CERTIFICATE-----
MIID/jCCAuagAwIBAgIQFaxulBmyeUtB9iepwxgPHzANBgkqhkiG9w0BAQsFADCB
mDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUdlb1RydXN0IEluYy4xOTA3BgNVBAsT
@@ -1832,27 +2253,40 @@ AWh9jUGhlBjBJVz88P6DAod8DQ3PLghcSkANPuyBYeYk28rgDi0Hsj5W3I31QYUH
SJsMC8tJP33st/3LjWeJGqvtux6jAAgIFyqCXDFdRootD4abdNlF+9RAsXqqaC2G
spki4cErx5z481+oghLrGREt
-----END CERTIFICATE-----
+# "Global Chambersign Root"
+# EF 3C B4 17 FC 8E BF 6F 97 87 6C 9E 4E CE 39 DE
+# 1E A5 FE 64 91 41 D1 02 8B 7D 11 C0 B2 29 8C ED
-----BEGIN CERTIFICATE-----
-MIIDfDCCAmSgAwIBAgIQGKy1av1pthU6Y2yv2vrEoTANBgkqhkiG9w0BAQUFADBY
-MQswCQYDVQQGEwJVUzEWMBQGA1UEChMNR2VvVHJ1c3QgSW5jLjExMC8GA1UEAxMo
-R2VvVHJ1c3QgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTAeFw0wNjEx
-MjcwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMFgxCzAJBgNVBAYTAlVTMRYwFAYDVQQK
-Ew1HZW9UcnVzdCBJbmMuMTEwLwYDVQQDEyhHZW9UcnVzdCBQcmltYXJ5IENlcnRp
-ZmljYXRpb24gQXV0aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC
-AQEAvrgVe//UfH1nrYNke8hCUy3f9oQIIGHWAVlqnEQRr+92/ZV+zmEwu3qDXwK9
-AWbK7hWNb6EwnL2hhZ6UOvNWiAAxz9juapYC2e0DjPt1befquFUWBRaa9OBesYjA
-ZIVcFU2Ix7e64HXprQU9nceJSOC7KMgD4TCTZF5SwFlwIjVXiIrxlQqD17wxcwE0
-7e9GceBrAqg1cmuXm2bgyxx5X9gaBGgeRwLmnWDiNpcB3841kt++Z8dtd1k7j53W
-kBWUvEI0EME5+bEnPn7WinXFsq+W06Lem+SYvn3h6YGttm/81w7a4DSwDRp35+MI
-mO9Y+pyEtzavwt+s0vQQBnBxNQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4G
-A1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQULNVQQZcVi/CPNmFbSvtr2ZnJM5IwDQYJ
-KoZIhvcNAQEFBQADggEBAFpwfyzdtzRP9YZRqSa+S7iq8XEN3GHHoOo0Hnp3DwQ1
-6CePbJC/kRYkRj5KTs4rFtULUh38H2eiAkUxT87z+gOneZ1TatnaYzr4gNfTmeGl
-4b7UVXGYNTq+k+qurUKykG/g/CFNNWMziUnWm07Kx+dOCQD32sfvmWKZd7aVIl6K
-oKv0uHiYyjgZmclynnjNS6yvGaBzEi38wkG6gZHaFloxt/m0cYASSJlyc1pZU8Fj
-UjPtp8nSOQJw+uCxQmYpqptR7TBUIhRf2asdweSU8Pj1K/fqynhG1riR/aYNKxoU
-AT6A8EKglQdebc3MS6RFjasS6LPeWuWgfOgPIh1a6Vk=
+MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
+MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
+ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
+YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
+MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
+NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
+A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
+A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
+Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
+QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
+eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
+B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
+z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
+AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
+ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
+TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
+MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
+VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
+VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
+bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
+AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
+bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
+ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
+VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
+ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
+AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
-----END CERTIFICATE-----
+# "Global Chambersign Root - 2008"
+# 13 63 35 43 93 34 A7 69 80 16 A0 D3 24 DE 72 28
+# 4E 07 9D 7B 52 20 BB 8F BD 74 78 16 EE BE BA CA
-----BEGIN CERTIFICATE-----
MIIHSTCCBTGgAwIBAgIJAMnN0+nVfSPOMA0GCSqGSIb3DQEBBQUAMIGsMQswCQYD
VQQGEwJFVTFDMEEGA1UEBxM6TWFkcmlkIChzZWUgY3VycmVudCBhZGRyZXNzIGF0
@@ -1894,82 +2328,9 @@ M0LpRQp8bfKGeS/Fghl9CYl8slR2iK7ewfPM4W7bMdaTrpmg7yVqc5iJWzouE4ge
v8CSlDQb4ye3ix5vQv/n6TebUB0tovkC7stYWDpxvGjjqsGvHCgfotwjZT+B6q6Z
09gwzxMNTxXJhLynSC34MCN32EZLeW32jO06f2ARePTpm67VVMB0gNELQp/B
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIExTCCA62gAwIBAgIBADANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJFVTEn
-MCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgyNzQzMjg3MSMwIQYDVQQL
-ExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4GA1UEAxMXR2xvYmFsIENo
-YW1iZXJzaWduIFJvb3QwHhcNMDMwOTMwMTYxNDE4WhcNMzcwOTMwMTYxNDE4WjB9
-MQswCQYDVQQGEwJFVTEnMCUGA1UEChMeQUMgQ2FtZXJmaXJtYSBTQSBDSUYgQTgy
-NzQzMjg3MSMwIQYDVQQLExpodHRwOi8vd3d3LmNoYW1iZXJzaWduLm9yZzEgMB4G
-A1UEAxMXR2xvYmFsIENoYW1iZXJzaWduIFJvb3QwggEgMA0GCSqGSIb3DQEBAQUA
-A4IBDQAwggEIAoIBAQCicKLQn0KuWxfH2H3PFIP8T8mhtxOviteePgQKkotgVvq0
-Mi+ITaFgCPS3CU6gSS9J1tPfnZdan5QEcOw/Wdm3zGaLmFIoCQLfxS+EjXqXd7/s
-QJ0lcqu1PzKY+7e3/HKE5TWH+VX6ox8Oby4o3Wmg2UIQxvi1RMLQQ3/bvOSiPGpV
-eAp3qdjqGTK3L/5cPxvusZjsyq16aUXjlg9V9ubtdepl6DJWk0aJqCWKZQbua795
-B9Dxt6/tLE2Su8CoX6dnfQTyFQhwrJLWfQTSM/tMtgsL+xrJxI0DqX5c8lCrEqWh
-z0hQpe/SyBoT+rB/sYIcd2oPX9wLlY/vQ37mRQklAgEDo4IBUDCCAUwwEgYDVR0T
-AQH/BAgwBgEB/wIBDDA/BgNVHR8EODA2MDSgMqAwhi5odHRwOi8vY3JsLmNoYW1i
-ZXJzaWduLm9yZy9jaGFtYmVyc2lnbnJvb3QuY3JsMB0GA1UdDgQWBBRDnDafsJ4w
-TcbOX60Qq+UDpfqpFDAOBgNVHQ8BAf8EBAMCAQYwEQYJYIZIAYb4QgEBBAQDAgAH
-MCoGA1UdEQQjMCGBH2NoYW1iZXJzaWducm9vdEBjaGFtYmVyc2lnbi5vcmcwKgYD
-VR0SBCMwIYEfY2hhbWJlcnNpZ25yb290QGNoYW1iZXJzaWduLm9yZzBbBgNVHSAE
-VDBSMFAGCysGAQQBgYcuCgEBMEEwPwYIKwYBBQUHAgEWM2h0dHA6Ly9jcHMuY2hh
-bWJlcnNpZ24ub3JnL2Nwcy9jaGFtYmVyc2lnbnJvb3QuaHRtbDANBgkqhkiG9w0B
-AQUFAAOCAQEAPDtwkfkEVCeR4e3t/mh/YV3lQWVPMvEYBZRqHN4fcNs+ezICNLUM
-bKGKfKX0j//U2K0X1S0E0T9YgOKBWYi+wONGkyT+kL0mojAt6JcmVzWJdJYY9hXi
-ryQZVgICsroPFOrGimbBhkVVi76SvpykBMdJPJ7oKXqJ1/6v/2j1pReQvayZzKWG
-VwlnRtvWFsJG8eSpUPWP0ZIV018+xgBJOm5YstHRJw0lyDL4IBHNfTIzSJRUTN3c
-ecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREest2d/
-AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
-A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
-b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
-MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
-YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
-aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
-jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
-xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
-1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
-snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
-U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
-9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
-AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
-yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
-38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
-AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
-DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
-HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
-FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
-DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
-uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
-kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
-ewv4n4Q=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
-MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
-bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
-DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
-QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
-MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
-8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
-hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
-VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
-KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
-515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
-xwy8p2Fp8fc74SrL+SvzZpA3
------END CERTIFICATE-----
+# "GlobalSign"
+# CA 42 DD 41 74 5F D0 B8 1E B9 02 36 2C F9 D8 BF
+# 71 9D A1 BD 1B 1E FC 94 6F 5B 4C 99 F4 2C 1B 9E
-----BEGIN CERTIFICATE-----
MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
@@ -1992,6 +2353,9 @@ ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
-----END CERTIFICATE-----
+# "GlobalSign"
+# CB B5 22 D7 B7 F1 27 AD 6A 01 13 86 5B DF 1C D4
+# 10 2E 7D 07 59 AF 63 5A 7C F4 72 0D C9 63 C5 3B
-----BEGIN CERTIFICATE-----
MIIDXzCCAkegAwIBAgILBAAAAAABIVhTCKIwDQYJKoZIhvcNAQELBQAwTDEgMB4G
A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjMxEzARBgNVBAoTCkdsb2JhbFNp
@@ -2013,6 +2377,66 @@ mcIfeg7jLQitChws/zyrVQ4PkX4268NXSb7hLi18YIvDQVETI53O9zJrlAGomecs
Mx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7rkpeDMdmztcpH
WD9f
-----END CERTIFICATE-----
+# "GlobalSign"
+# BE C9 49 11 C2 95 56 76 DB 6C 0A 55 09 86 D7 6E
+# 3B A0 05 66 7C 44 2C 97 62 B4 FB B7 73 DE 22 8C
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAYegAwIBAgIRKjikHJYKBN5CsiilC+g0mAIwCgYIKoZIzj0EAwIwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI0MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI0MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEuMZ5049sJQ6fLjkZHAOkrprlOQcJ
+FspjsbmG+IpXwVfOQvpzofdlQv8ewQCybnMO/8ch5RikqtlxP6jUuc6MHaNCMEAw
+DgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFFSwe61F
+uOJAf/sKbvu+M8k8o4TVMAoGCCqGSM49BAMCA0gAMEUCIQDckqGgE6bPA7DmxCGX
+kPoUVy0D7O48027KqGx2vKLeuwIgJ6iFJzWbVsaj8kfSt24bAgAXqmemFZHe+pTs
+ewv4n4Q=
+-----END CERTIFICATE-----
+# "GlobalSign"
+# 17 9F BC 14 8A 3D D0 0F D2 4E A1 34 58 CC 43 BF
+# A7 F5 9C 81 82 D7 83 A5 13 F6 EB EC 10 0C 89 24
+-----BEGIN CERTIFICATE-----
+MIICHjCCAaSgAwIBAgIRYFlJ4CYuu1X5CneKcflK2GwwCgYIKoZIzj0EAwMwUDEk
+MCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBDQSAtIFI1MRMwEQYDVQQKEwpH
+bG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWduMB4XDTEyMTExMzAwMDAwMFoX
+DTM4MDExOTAzMTQwN1owUDEkMCIGA1UECxMbR2xvYmFsU2lnbiBFQ0MgUm9vdCBD
+QSAtIFI1MRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpHbG9iYWxTaWdu
+MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAER0UOlvt9Xb/pOdEh+J8LttV7HpI6SFkc
+8GIxLcB6KP4ap1yztsyX50XUWPrRd21DosCHZTQKH3rd6zwzocWdTaRvQZU4f8ke
+hOvRnkmSh5SHDDqFSmafnVmTTZdhBoZKo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYD
+VR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUPeYpSJvqB8ohREom3m7e0oPQn1kwCgYI
+KoZIzj0EAwMDaAAwZQIxAOVpEslu28YxuglB4Zf4+/2a4n0Sye18ZNPLBSWLVtmg
+515dTguDnFt2KaAJJiFqYgIwcdK1j1zqO+F4CYWodZI7yFz9SO8NdCKoCOJuxUnO
+xwy8p2Fp8fc74SrL+SvzZpA3
+-----END CERTIFICATE-----
+# "GlobalSign Root CA"
+# EB D4 10 40 E4 BB 3E C7 42 C9 E3 81 D3 1E F2 A4
+# 1A 48 B6 68 5C 96 E7 CE F3 C1 DF 6C D4 33 1C 99
+-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----
+# "Go Daddy Class 2 Certification Authority"
+# C3 84 6B F2 4B 9E 93 CA 64 27 4C 0E C6 7C 1E CC
+# 5E 02 4F FC AC D2 D7 40 19 35 0E 81 FE 54 6A E4
-----BEGIN CERTIFICATE-----
MIIEADCCAuigAwIBAgIBADANBgkqhkiG9w0BAQUFADBjMQswCQYDVQQGEwJVUzEh
MB8GA1UEChMYVGhlIEdvIERhZGR5IEdyb3VwLCBJbmMuMTEwLwYDVQQLEyhHbyBE
@@ -2037,6 +2461,9 @@ HmyW74cNxA9hi63ugyuV+I6ShHI56yDqg+2DzZduCLzrTia2cyvk0/ZM/iZx4mER
dEr/VxqHD3VILs9RaRegAhJhldXRQLIQTO7ErBBDpqWeCtWVYpoNz4iCxTIM5Cuf
ReYNnyicsbkqWletNw+vHX/bvZ8=
-----END CERTIFICATE-----
+# "Go Daddy Root Certificate Authority - G2"
+# 45 14 0B 32 47 EB 9C C8 C5 B4 F0 D7 B5 30 91 F7
+# 32 92 08 9E 6E 5A 63 E2 74 9D D3 AC A9 19 8E DA
-----BEGIN CERTIFICATE-----
MIIDxTCCAq2gAwIBAgIBADANBgkqhkiG9w0BAQsFADCBgzELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxGjAYBgNVBAoT
@@ -2060,6 +2487,9 @@ gIOrmgIttRD02JDHBHNA7XIloKmf7J6raBKZV8aPEjoJpL1E/QYVN8Gb5DKj7Tjo
LPAvTK33sefOT6jEm0pUBsV/fdUID+Ic/n4XuKxe9tQWskMJDE32p2u0mYRlynqI
4uJEvlz36hz1
-----END CERTIFICATE-----
+# "Government Root Certification Authority"
+# 70 B9 22 BF DA 0E 3F 4A 34 2E 4E E2 2D 57 9A E5
+# 98 D0 71 CC 5E C9 C3 0F 12 36 80 34 03 88 AE A5
-----BEGIN CERTIFICATE-----
MIIFSzCCAzOgAwIBAgIRALZLiAfiI+7IXBKtpg4GofIwDQYJKoZIhvcNAQELBQAw
PzELMAkGA1UEBhMCVFcxMDAuBgNVBAoMJ0dvdmVybm1lbnQgUm9vdCBDZXJ0aWZp
@@ -2091,6 +2521,129 @@ uoJxo4ZVKZnSKdt1OvfbQ/+2W/u3fjWAjg1srnm3Ni2XUqGwB5wH5Ss2zQOXlL0t
DjQG/MAWifw3VOTWzz0TBPKR2ck2Lj7FWtClTILD/y58Jnb38/1FoqVuVa4uzM8s
iTTa9g3nkagQ6hed8vbs
-----END CERTIFICATE-----
+# "GTS Root R1"
+# 2A 57 54 71 E3 13 40 BC 21 58 1C BD 2C F1 3E 15
+# 84 63 20 3E CE 94 BC F9 D3 CC 19 6B F0 9A 54 72
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxUtHDA3sM9CJuRz04TANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaM
+f/vo27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vX
+mX7wCl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7
+zUjwTcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0P
+fyblqAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtc
+vfaHszVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4
+Zor8Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUsp
+zBmkMiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOO
+Rc92wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYW
+k70paDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+
+DVrNVjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgF
+lQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBADiW
+Cu49tJYeX++dnAsznyvgyv3SjgofQXSlfKqE1OXyHuY3UjKcC9FhHb8owbZEKTV1
+d5iyfNm9dKyKaOOpMQkpAWBz40d8U6iQSifvS9efk+eCNs6aaAyC58/UEBZvXw6Z
+XPYfcX3v73svfuo21pdwCxXu11xWajOl40k4DLh9+42FpLFZXvRq4d2h9mREruZR
+gyFmxhE+885H7pwoHyXa/6xmld01D1zvICxi/ZG6qcz8WpyTgYMpl0p8WnK0OdC3
+d8t5/Wk6kjftbjhlRn7pYL15iJdfOBL07q9bgsiG1eGZbYwE8na6SfZu6W0eX6Dv
+J4J2QPim01hcDyxC2kLGe4g0x8HYRZvBPsVhHdljUEn2NIVq4BjFbkerQUIpm/Zg
+DdIx02OYI5NaAIFItO/Nis3Jz5nu2Z6qNuFoS3FJFDYoOj0dzpqPJeaAcWErtXvM
++SUWgeExX6GjfhaknBZqlxi9dnKlC54dNuYvoS++cJEPqOba+MSSQGwlfnuzCdyy
+F62ARPBopY+Udf90WuioAnwMCeKpSwughQtiue+hMZL77/ZRBIls6Kl0obsXs7X9
+SQ98POyDGCBDTtWTurQ0sR8WNh8M5mQ5Fkzc4P4dyKliPUDqysU0ArSuiYgzNdws
+E3PYJ/HQcu51OyLemGhmW/HGY0dVHLqlCFF1pkgl
+-----END CERTIFICATE-----
+# "GTS Root R2"
+# C4 5D 7B B0 8E 6D 67 E6 2E 42 35 11 0B 56 4E 5F
+# 78 FD 92 EF 05 8C 84 0A EA 4E 64 55 D7 58 5C 60
+-----BEGIN CERTIFICATE-----
+MIIFWjCCA0KgAwIBAgIQbkepxlqz5yDFMJo/aFLybzANBgkqhkiG9w0BAQwFADBH
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIy
+MDAwMDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNl
+cnZpY2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQDO3v2m++zsFDQ8BwZabFn3GTXd98GdVarTzTukk3Lv
+CvptnfbwhYBboUhSnznFt+4orO/LdmgUud+tAWyZH8QiHZ/+cnfgLFuv5AS/T3Kg
+GjSY6Dlo7JUle3ah5mm5hRm9iYz+re026nO8/4Piy33B0s5Ks40FnotJk9/BW9Bu
+XvAuMC6C/Pq8tBcKSOWIm8Wba96wyrQD8Nr0kLhlZPdcTK3ofmZemde4wj7I0BOd
+re7kRXuJVfeKH2JShBKzwkCX44ofR5GmdFrS+LFjKBC4swm4VndAoiaYecb+3yXu
+PuWgf9RhD1FLPD+M2uFwdNjCaKH5wQzpoeJ/u1U8dgbuak7MkogwTZq9TwtImoS1
+mKPV+3PBV2HdKFZ1E66HjucMUQkQdYhMvI35ezzUIkgfKtzra7tEscszcTJGr61K
+8YzodDqs5xoic4DSMPclQsciOzsSrZYuxsN2B6ogtzVJV+mSSeh2FnIxZyuWfoqj
+x5RWIr9qS34BIbIjMt/kmkRtWVtd9QCgHJvGeJeNkP+byKq0rxFROV7Z+2et1VsR
+nTKaG73VululycslaVNVJ1zgyjbLiGH7HrfQy+4W+9OmTN6SpdTi3/UGVN4unUu0
+kzCqgc7dGtxRcw1PcOnlthYhGXmy5okLdWTK1au8CcEYof/UVKGFPP0UJAOyh9Ok
+twIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNV
+HQ4EFgQUu//KjiOfT5nK2+JopqUVJxce2Q4wDQYJKoZIhvcNAQEMBQADggIBALZp
+8KZ3/p7uC4Gt4cCpx/k1HUCCq+YEtN/L9x0Pg/B+E02NjO7jMyLDOfxA325BS0JT
+vhaI8dI4XsRomRyYUpOM52jtG2pzegVATX9lO9ZY8c6DR2Dj/5epnGB3GFW1fgiT
+z9D2PGcDFWEJ+YF59exTpJ/JjwGLc8R3dtyDovUMSRqodt6Sm2T4syzFJ9MHwAiA
+pJiS4wGWAqoC7o87xdFtCjMwc3i5T1QWvwsHoaRc5svJXISPD+AVdyx+Jn7axEvb
+pxZ3B7DNdehyQtaVhJ2Gg/LkkM0JR9SLA3DaWsYDQvTtN6LwG1BUSw7YhN4ZKJmB
+R64JGz9I0cNv4rBgF/XuIwKl2gBbbZCr7qLpGzvpx0QnRY5rn/WkhLx3+WuXrD5R
+RaIRpsyF7gpo8j5QOHokYh4XIDdtak23CZvJ/KRY9bb7nE4Yu5UC56GtmwfuNmsk
+0jmGwZODUNKBRqhfYlcsu2xkiAhu7xNUX90txGdj08+JN7+dIPT7eoOboB6BAFDC
+5AwiWVIQ7UNWhwD4FFKnHYuTjKJNRn8nxnGbJN7k2oaLDX5rIMHAnuFl2GqjpuiF
+izoHCBy69Y9Vmhh1fuXsgWbRIXOhNUQLgD1bnF5vKheW0YMjiGZt5obicDIvUiLn
+yOd/xCxgXS/Dr55FBcOEArf9LAhST4Ldo/DUhgkC
+-----END CERTIFICATE-----
+# "GTS Root R3"
+# 15 D5 B8 77 46 19 EA 7D 54 CE 1C A6 D0 B0 C4 03
+# E0 37 A9 17 F1 31 E8 A0 4E 1E 6B 7A 71 BA BC E5
+-----BEGIN CERTIFICATE-----
+MIICDDCCAZGgAwIBAgIQbkepx2ypcyRAiQ8DVd2NHTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjMwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjMwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQfTzOHMymKoYTey8chWEGJ6ladK0uFxh1MJ7x/JlFyb+Kf1qPKzEUURout
+736GjOyxfi//qXGdGIRFBEFVbivqJn+7kAHjSxm65FSWRQmx1WyRRK2EE46ajA2A
+DDL24CejQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBTB8Sa6oC2uhYHP0/EqEr24Cmf9vDAKBggqhkjOPQQDAwNpADBmAjEAgFuk
+fCPAlaUs3L6JbyO5o91lAFJekazInXJ0glMLfalAvWhgxeG4VDvBNhcl2MG9AjEA
+njWSdIUlUfUk7GRSJFClH9voy8l27OyCbvWFGFPouOOaKaqW04MjyaR7YbPMAuhd
+-----END CERTIFICATE-----
+# "GTS Root R4"
+# 71 CC A5 39 1F 9E 79 4B 04 80 25 30 B3 63 E1 21
+# DA 8A 30 43 BB 26 66 2F EA 4D CA 7F C9 51 A4 BD
+-----BEGIN CERTIFICATE-----
+MIICCjCCAZGgAwIBAgIQbkepyIuUtui7OyrYorLBmTAKBggqhkjOPQQDAzBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjQwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjQwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAATzdHOnaItgrkO4NcWBMHtLSZ37wWHO5t5GvWvVYRg1rkDdc/eJkTBa6zzu
+hXyiQHY7qca4R9gq55KRanPpsXI5nymfopjTX15YhmUPoYRlBtHci8nHc8iMai/l
+xKvRHYqjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1Ud
+DgQWBBSATNbrdP9JNqPV2Py1PsVq8JQdjDAKBggqhkjOPQQDAwNnADBkAjBqUFJ0
+CMRw3J5QdCHojXohw0+WbhXRIjVhLfoIN+4Zba3bssx9BzT1YBkstTTZbyACMANx
+sbqjYAuG7ZoIapVon+Kz4ZNkfF6Tpt95LY2F45TPI11xzPKwTdb+mciUqXWi4w==
+-----END CERTIFICATE-----
+# "Hellenic Academic and Research Institutions ECC RootCA 2015"
+# 44 B5 45 AA 8A 25 E6 5A 73 CA 15 DC 27 FC 36 D2
+# 4C 1C B9 95 3A 06 65 39 B1 15 82 DC 48 7B 48 33
+-----BEGIN CERTIFICATE-----
+MIICwzCCAkqgAwIBAgIBADAKBggqhkjOPQQDAjCBqjELMAkGA1UEBhMCR1IxDzAN
+BgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5kIFJl
+c2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxRDBCBgNVBAMTO0hl
+bGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgRUNDIFJv
+b3RDQSAyMDE1MB4XDTE1MDcwNzEwMzcxMloXDTQwMDYzMDEwMzcxMlowgaoxCzAJ
+BgNVBAYTAkdSMQ8wDQYDVQQHEwZBdGhlbnMxRDBCBgNVBAoTO0hlbGxlbmljIEFj
+YWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgQ2VydC4gQXV0aG9yaXR5
+MUQwQgYDVQQDEztIZWxsZW5pYyBBY2FkZW1pYyBhbmQgUmVzZWFyY2ggSW5zdGl0
+dXRpb25zIEVDQyBSb290Q0EgMjAxNTB2MBAGByqGSM49AgEGBSuBBAAiA2IABJKg
+QehLgoRc4vgxEZmGZE4JJS+dQS8KrjVPdJWyUWRrjWvmP3CV8AVER6ZyOFB2lQJa
+jq4onvktTpnvLEhvTCUp6NFxW98dwXU3tNf6e3pCnGoKVlp8aQuqgAkkbH7BRqNC
+MEAwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYDVR0OBBYEFLQi
+C4KZJAEOnLvkDv2/+5cgk5kqMAoGCCqGSM49BAMCA2cAMGQCMGfOFmI4oqxiRaep
+lSTAGiecMjvAwNW6qef4BENThe5SId6d9SWDPp5YSy/XZxMOIQIwBeF1Ad5o7Sof
+TUwJCA3sS61kFyjndc5FZXIhF8siQQ6ME5g4mlRtm8rifOoCWCKR
+-----END CERTIFICATE-----
+# "Hellenic Academic and Research Institutions RootCA 2011"
+# BC 10 4F 15 A4 8B E7 09 DC A5 42 A7 E1 D4 B9 DF
+# 6F 05 45 27 E8 02 EA A9 2D 59 54 44 25 8A FE 71
-----BEGIN CERTIFICATE-----
MIIEMTCCAxmgAwIBAgIBADANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UEBhMCR1Ix
RDBCBgNVBAoTO0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
@@ -2116,6 +2669,47 @@ dIsXRSZMFpGD/md9zU1jZ/rzAxKWeAaNsWftjj++n08C9bMJL/NMh98qy5V8Acys
Nnq/onN694/BtZqhFLKPM58N7yLcZnuEvUUXBj08yrl3NI/K6s8/MT7jiOOASSXI
l7WdmplNsDz4SgCbZN2fOUvRJ9e4
-----END CERTIFICATE-----
+# "Hellenic Academic and Research Institutions RootCA 2015"
+# A0 40 92 9A 02 CE 53 B4 AC F4 F2 FF C6 98 1C E4
+# 49 6F 75 5E 6D 45 FE 0B 2A 69 2B CD 52 52 3F 36
+-----BEGIN CERTIFICATE-----
+MIIGCzCCA/OgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBpjELMAkGA1UEBhMCR1Ix
+DzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNhZGVtaWMgYW5k
+IFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkxQDA+BgNVBAMT
+N0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1dGlvbnMgUm9v
+dENBIDIwMTUwHhcNMTUwNzA3MTAxMTIxWhcNNDAwNjMwMTAxMTIxWjCBpjELMAkG
+A1UEBhMCR1IxDzANBgNVBAcTBkF0aGVuczFEMEIGA1UEChM7SGVsbGVuaWMgQWNh
+ZGVtaWMgYW5kIFJlc2VhcmNoIEluc3RpdHV0aW9ucyBDZXJ0LiBBdXRob3JpdHkx
+QDA+BgNVBAMTN0hlbGxlbmljIEFjYWRlbWljIGFuZCBSZXNlYXJjaCBJbnN0aXR1
+dGlvbnMgUm9vdENBIDIwMTUwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC
+AQDC+Kk/G4n8PDwEXT2QNrCROnk8ZlrvbTkBSRq0t89/TSNTt5AA4xMqKKYx8ZEA
+4yjsriFBzh/a/X0SWwGDD7mwX5nh8hKDgE0GPt+sr+ehiGsxr/CL0BgzuNtFajT0
+AoAkKAoCFZVedioNmToUW/bLy1O8E00BiDeUJRtCvCLYjqOWXjrZMts+6PAQZe10
+4S+nfK8nNLspfZu2zwnI5dMK/IhlZXQK3HMcXM1AsRzUtoSMTFDPaI6oWa7CJ06C
+ojXdFPQf/7J31Ycvqm59JCfnxssm5uX+Zwdj2EUN3TpZZTlYepKZcj2chF6IIbjV
+9Cz82XBST3i4vTwri5WY9bPRaM8gFH5MXF/ni+X1NYEZN9cRCLdmvtNKzoNXADrD
+gfgXy5I2XdGj2HUb4Ysn6npIQf1FGQatJ5lOwXBH3bWfgVMS5bGMSF0xQxfjjMZ6
+Y5ZLKTBOhE5iGV48zpeQpX8B653g+IuJ3SWYPZK2fu/Z8VFRfS0myGlZYeCsargq
+NhEEelC9MoS+L9xy1dcdFkfkR2YgP/SWxa+OAXqlD3pk9Q0Yh9muiNX6hME6wGko
+LfINaFGq46V3xqSQDqE3izEjR8EJCOtu93ib14L8hCCZSRm2Ekax+0VVFqmjZayc
+Bw/qa9wfLgZy7IaIEuQt218FL+TwA9MmM+eAws1CoRc0CwIDAQABo0IwQDAPBgNV
+HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUcRVnyMjJvXVd
+ctA4GGqd83EkVAswDQYJKoZIhvcNAQELBQADggIBAHW7bVRLqhBYRjTyYtcWNl0I
+XtVsyIe9tC5G8jH4fOpCtZMWVdyhDBKg2mF+D1hYc2Ryx+hFjtyp8iY/xnmMsVMI
+M4GwVhO+5lFc2JsKT0ucVlMC6U/2DWDqTUJV6HwbISHTGzrMd/K4kPFox/la/vot
+9L/J9UUbzjgQKjeKeaO04wlshYaT/4mWJ3iBj2fjRnRUjtkNaeJK9E10A/+yd+2V
+Z5fkscWrv2oj6NSU4kQoYsRL4vDY4ilrGnB+JGGTe08DMiUNRSQrlrRGar9KC/ea
+j8GsGsVn82800vpzY4zvFrCopEYq+OsS7HK07/grfoxSwIuEVPkvPuNVqNxmsdnh
+X9izjFk0WaSrT2y7HxjbdavYy5LNlDhhDgcGH0tGEPEVvo2FXDtKK4F5D7Rpn0lQ
+l033DlZdwJVqwjbDG2jJ9SrcR5q+ss7FJej6A7na+RZukYT1HCjI/CbM1xyQVqdf
+bzoEvM14iQuODy+jqk+iGxI9FghAD/FGTNeqewjBCvVtJ94Cj8rDtSvK6evIIVM4
+pcw72Hc3MKJP2W/R8kCtQXoXxdZKNYm3QdV8hn9VTYNKpXMgwDqvkPGaJI7ZjnHK
+e7iG2rKPmT4dEw0SEe7Uq/DpFXYC5ODfqiAeW2GFZECpkJcNrVPSWh2HagCXZWK0
+vm9qp/UsQu0yrbYhnr68
+-----END CERTIFICATE-----
+# "Hongkong Post Root CA 1"
+# F9 E6 7D 33 6C 51 00 2A C0 54 C6 32 02 2D 66 DD
+# A2 E7 E3 FF F1 0A D0 61 ED 31 D8 BB B4 10 CF B2
-----BEGIN CERTIFICATE-----
MIIDMDCCAhigAwIBAgICA+gwDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UEBhMCSEsx
FjAUBgNVBAoTDUhvbmdrb25nIFBvc3QxIDAeBgNVBAMTF0hvbmdrb25nIFBvc3Qg
@@ -2136,6 +2730,9 @@ EhTkYY2sEJCehFC78JZvRZ+K88psT/oROhUVRsPNH4NbLUES7VBnQRM9IauUiqpO
fMGx+6fWtScvl6tu4B3i0RwsH0Ti/L6RoZz71ilTc4afU9hDDl3WY4JxHYB0yvbi
AmvZWg==
-----END CERTIFICATE-----
+# "I.CA - Qualified Certification Authority, 09/2009"
+# C0 C0 5A 8D 8D A5 5E AF 27 AA 9B 91 0B 0A 6E F0
+# D8 BB DE D3 46 92 8D B8 72 E1 82 C2 07 3E 98 02
-----BEGIN CERTIFICATE-----
MIIFHjCCBAagAwIBAgIEAKA3oDANBgkqhkiG9w0BAQsFADCBtzELMAkGA1UEBhMC
Q1oxOjA4BgNVBAMMMUkuQ0EgLSBRdWFsaWZpZWQgQ2VydGlmaWNhdGlvbiBBdXRo
@@ -2166,6 +2763,9 @@ wvNdjG+nPzCJOOuUEypIWt555ZDLXqS5F7ZjBjlfyDZjEfS2Es9Idok8alf563Mi
9/o+Ba46wMYOkk3P1IlU0RqCajdbliioACKDztAqubONU1guZVzV8tuMASVzbJeL
/GAB7ECTwe1RuKrLYtglMKI9
-----END CERTIFICATE-----
+# "IdenTrust Commercial Root CA 1"
+# 5D 56 49 9B E4 D2 E0 8B CF CA D0 8A 3E 38 72 3D
+# 50 50 3B DE 70 69 48 E4 2F 55 60 30 19 E5 28 AE
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIQCgFCgAAAAUUjyES1AAAAAjANBgkqhkiG9w0BAQsFADBK
MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MScwJQYDVQQDEx5JZGVu
@@ -2197,6 +2797,9 @@ l1gEIt44w8y8bckzOmoKaT+gyOpyj4xjhiO9bTyWnpXgSUyqorkqG5w2gXjtw+hG
mUlO+KWA2yUPHGNiiskzZ2s8EIPGrd6ozRaOjfAHN3Gf8qv8QfXBi+wAN10J5U6A
7/qxXDgGpRtK4dw4LTzcqx+QGtVKnO7RcGzM7vRX+Bi6hG6H
-----END CERTIFICATE-----
+# "IdenTrust Public Sector Root CA 1"
+# 30 D0 89 5A 9A 44 8A 26 20 91 63 55 22 D1 F5 20
+# 10 B5 86 7A CA E1 2C 78 EF 95 8F D4 F4 38 9F 2F
-----BEGIN CERTIFICATE-----
MIIFZjCCA06gAwIBAgIQCgFCgAAAAUUjz0Z8AAAAAjANBgkqhkiG9w0BAQsFADBN
MQswCQYDVQQGEwJVUzESMBAGA1UEChMJSWRlblRydXN0MSowKAYDVQQDEyFJZGVu
@@ -2228,6 +2831,9 @@ tshquDDIajjDbp7hNxbqBWJMWxJH7ae0s1hWx0nzfxJoCTFx8G34Tkf71oXuxVhA
GaQdp/lLQzfcaFpPz+vCZHTetBXZ9FRUGi8c15dxVJCO2SCdUyt/q4/i6jC8UDfv
8Ue1fXwsBOxonbRJRBD0ckscZOf85muQ3Wl9af0AVqW3rLatt8o+Ae+c
-----END CERTIFICATE-----
+# "ISRG Root X1"
+# 96 BC EC 06 26 49 76 F3 74 60 77 9A CF 28 C5 A7
+# CF E8 A3 C0 AA E1 1A 8F FC EE 05 C0 BD DF 08 C6
-----BEGIN CERTIFICATE-----
MIIFazCCA1OgAwIBAgIRAIIQz7DSQONZRGPgu2OCiwAwDQYJKoZIhvcNAQELBQAw
TzELMAkGA1UEBhMCVVMxKTAnBgNVBAoTIEludGVybmV0IFNlY3VyaXR5IFJlc2Vh
@@ -2259,32 +2865,9 @@ oyi3B43njTOQ5yOf+1CceWxG1bQVs5ZufpsMljq4Ui0/1lvh+wjChP4kqKOJ2qxq
mRGunUHBcnWEvgJBQl9nJEiU0Zsnvgc/ubhPgXRR4Xq37Z0j4r7g1SgEEzwxA57d
emyPxgcYxn/eR44/KJ4EBs+lVDR3veyJm+kXQ99b21/+jh5Xos1AnX5iItreGCc=
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEXzCCA0egAwIBAgIBATANBgkqhkiG9w0BAQUFADCB0DELMAkGA1UEBhMCRVMx
-SDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMuVml0
-b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwgTWVk
-aXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6MRMw
-EQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5wZS5j
-b20wHhcNMDMwMTMwMjMwMDAwWhcNMTgwMTMwMjMwMDAwWjCB0DELMAkGA1UEBhMC
-RVMxSDBGBgNVBAoTP0laRU5QRSBTLkEuIC0gQ0lGIEEtMDEzMzcyNjAtUk1lcmMu
-Vml0b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFCMEAGA1UEBxM5QXZkYSBkZWwg
-TWVkaXRlcnJhbmVvIEV0b3JiaWRlYSAzIC0gMDEwMTAgVml0b3JpYS1HYXN0ZWl6
-MRMwEQYDVQQDEwpJemVucGUuY29tMR4wHAYJKoZIhvcNAQkBFg9JbmZvQGl6ZW5w
-ZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC1btoCXXhp3xIW
-D+Bxl8nUCxkyiazWfpt0e68t+Qt9+lZjKZSdEw2Omj4qvr+ovRmDXO3iWpWVOWDl
-3JHJjAzFCe8ZEBNDH+QNYwZHmPBaMYFOYFdbAFVHWvys152C308hcFJ6xWWGmjvl
-2eMiEl9P2nR2LWue368DCu+ak7j3gjAXaCOdP1a7Bfr+RW3X2SC5R4Xyp8iHlL5J
-PHJD/WBkLrezwzQPdACw8m9EG7q9kUwlNpL32mROujS3ZkT6mQTzJieLiE3X04s0
-uIUqVkk5MhjcHFf7al0N5CzjtTcnXYJKN2Z9EDVskk4olAdGi46eSoZXbjUOP5gk
-Ej6wVZAXAgMBAAGjQjBAMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEG
-MB0GA1UdDgQWBBTqVk/sPIOhFIh4gbIrBSLAB0FbQjANBgkqhkiG9w0BAQUFAAOC
-AQEAYp7mEzzhw6o5Hf5+T5kcI+t4BJyiIWy7vHlLs/G8dLYXO81aN/Mzg928eMTR
-TxxYZL8dd9uwsJ50TVfX6L0R4Dyw6wikh3fHRrat9ufXi63j5K91Ysr7aXqnF38d
-iAgHYkrwC3kuxHBb9C0KBz6h8Q45/KCyN7d37wWAq38yyhPDlaOvyoE6bdUuK5hT
-m5EYA5JmPyrhQ1moDOyueWBAjxzMEMj+OAY1H90cLv6wszsqerxRrdTOHBdv7MjB
-EIpvEEQkXUxVXAzFuuT6m2t91Lfnwfl/IvljHaVC7DlyyhRYHD6D4Rx+4QKp4tWL
-vpw6LkI+gKNJ/YdMCsRZQzEEFA==
------END CERTIFICATE-----
+# "Izenpe.com"
+# 23 80 42 03 CA 45 D8 CD E7 16 B8 C1 3B F3 B4 48
+# 45 7F A0 6C C1 02 50 99 7F A0 14 58 31 7C 41 E5
-----BEGIN CERTIFICATE-----
MIIF8DCCA9igAwIBAgIPBuhGJy8fCo/RhFzjafbVMA0GCSqGSIb3DQEBBQUAMDgx
CzAJBgNVBAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjETMBEGA1UEAwwKSXpl
@@ -2319,6 +2902,9 @@ pUTEvnK0jHS0bKf68r10OEMr3q/53NjgnZ/cPcqlY0S/kqJPTIAcuxrDmkoEVU3K
7iYLHL8CxWTTnn7S05EcS6L1HOUXHA0MUqORH5zwIe0ClG+poEnK6EOMxPQ02nwi
o8ZmPrgbBYhdurz3vOXcFD2nhqi2WVIhA16L4wTtSyoeo09Q
-----END CERTIFICATE-----
+# "Izenpe.com"
+# 25 30 CC 8E 98 32 15 02 BA D9 6F 9B 1F BA 1B 09
+# 9E 2D 29 9E 0F 45 48 BB 91 4F 36 3B C0 D4 53 1F
-----BEGIN CERTIFICATE-----
MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
@@ -2353,6 +2939,9 @@ QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
-----END CERTIFICATE-----
+# "KISA RootCA 1"
+# 6F DB 3F 76 C8 B8 01 A7 53 38 D8 A5 0A 7C 02 87
+# 9F 61 98 B5 7E 59 4D 31 8D 38 32 90 0F ED CD 79
-----BEGIN CERTIFICATE-----
MIIDczCCAlugAwIBAgIBBDANBgkqhkiG9w0BAQUFADBkMQswCQYDVQQGEwJLUjEN
MAsGA1UECgwES0lTQTEuMCwGA1UECwwlS29yZWEgQ2VydGlmaWNhdGlvbiBBdXRo
@@ -2374,6 +2963,9 @@ BM+tWh6UCVrXPAgcrnrpFDLBRa3SJkhyrKhB2vAhhzle3/xk/2F0KpzZm4tfwjeT
fi5C4e3nCSG9uRPFVmf0JqZCQ5BEVLRxm3bkGhKsGigA35vB1fjbXKP4krG9tNT5
UNkAAk/bg9ART6RCVmE6fhMy04Qfybo=
-----END CERTIFICATE-----
+# "Microsec e-Szigno Root CA 2009"
+# 3C 5F 81 FE A5 FA B8 2C 64 BF A2 EA EC AF CD E8
+# E0 77 FC 86 20 A7 CA E5 37 16 3D F3 6E DB F3 78
-----BEGIN CERTIFICATE-----
MIIECjCCAvKgAwIBAgIJAMJ+QwRORz8ZMA0GCSqGSIb3DQEBCwUAMIGCMQswCQYD
VQQGEwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFjAUBgNVBAoMDU1pY3Jvc2VjIEx0
@@ -2398,6 +2990,9 @@ tyERzAMBVnCnEJIeGzSBHq2cGsMEPO0CYdYeBvNfOofyK/FFh+U9rNHHV4S9a67c
2Pm2G2JwCz02yULyMtd6YebS2z3PyKnJm9zbWETXbzivf3jTo60adbocwTZ8jx5t
HMN1Rq41Bab2XD0h7lbwyYIiLXpUq3DDfSJlgnCW
-----END CERTIFICATE-----
+# "NetLock Arany (Class Gold) Főtanúsítvány"
+# 6C 61 DA C3 A2 DE F0 31 50 6B E0 36 D2 A6 FE 40
+# 19 94 FB D1 3D F9 C8 D4 66 59 92 74 C4 46 EC 98
-----BEGIN CERTIFICATE-----
MIIEFTCCAv2gAwIBAgIGSUEs5AAQMA0GCSqGSIb3DQEBCwUAMIGnMQswCQYDVQQG
EwJIVTERMA8GA1UEBwwIQnVkYXBlc3QxFTATBgNVBAoMDE5ldExvY2sgS2Z0LjE3
@@ -2422,6 +3017,9 @@ bLBQWV2QWzuoDTDPv31/zvGdg73JRm4gpvlhUbohL3u+pRVjodSVh/GeufOJ8z2F
uLjbvrW5KfnaNwUASZQDhETnv0Mxz3WLJdH0pmT1kvarBes96aULNmLazAZfNou2
XjG4Kvte9nHfRCaexOYNkbQudZWAUWpLMKawYqGT8ZvYzsRjdT9ZR7E=
-----END CERTIFICATE-----
+# "Network Solutions Certificate Authority"
+# 15 F0 BA 00 A3 AC 7A F3 AC 88 4C 07 2B 10 11 A0
+# 77 BD 77 C0 97 F4 01 64 B2 F8 59 8A BD 83 86 0C
-----BEGIN CERTIFICATE-----
MIID5jCCAs6gAwIBAgIQV8szb8JcFuZHFhfjkDFo4DANBgkqhkiG9w0BAQUFADBi
MQswCQYDVQQGEwJVUzEhMB8GA1UEChMYTmV0d29yayBTb2x1dGlvbnMgTC5MLkMu
@@ -2445,6 +3043,9 @@ h1AcgsLj4DKAv6ALR8jDMe+ZZzKATxcheQxpXN5eNK4CtSbqUN9/GGUsyfJj4akH
wKeI8lN3s2Berq4o2jUsbzRF0ybh3uxbTydrFny9RAQYgrOJeRcQcT16ohZO9QHN
pGxlaKFJdlxDydi8NmdspZS11My5vWo1ViHe2MPr+8ukYEywVaCge1ey
-----END CERTIFICATE-----
+# "OISTE WISeKey Global Root GA CA"
+# 41 C9 23 86 6A B4 CA D6 B7 AD 57 80 81 58 2E 02
+# 07 97 A6 CB DF 4F FF 78 CE 83 96 B3 89 37 D7 F5
-----BEGIN CERTIFICATE-----
MIID8TCCAtmgAwIBAgIQQT1yx/RrH4FDffHSKFTfmjANBgkqhkiG9w0BAQUFADCB
ijELMAkGA1UEBhMCQ0gxEDAOBgNVBAoTB1dJU2VLZXkxGzAZBgNVBAsTEkNvcHly
@@ -2469,6 +3070,9 @@ hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZi
Fj4A4xylNoEYokxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ
/L7fCg0=
-----END CERTIFICATE-----
+# "OISTE WISeKey Global Root GB CA"
+# 6B 9C 08 E8 6E B0 F7 67 CF AD 65 CD 98 B6 21 49
+# E5 49 4A 67 F5 84 5E 7B D1 ED 01 9F 27 B8 6B D6
-----BEGIN CERTIFICATE-----
MIIDtTCCAp2gAwIBAgIQdrEgUnTwhYdGs/gjGvbCwDANBgkqhkiG9w0BAQsFADBt
MQswCQYDVQQGEwJDSDEQMA4GA1UEChMHV0lTZUtleTEiMCAGA1UECxMZT0lTVEUg
@@ -2491,6 +3095,96 @@ ZvUPQ82nK1d7Y0Zqqi5S2PTt4W2tKZB4SLrhI6qjiey1q5bAtEuiHZeeevJuQHHf
aPFlTc58Bd9TZaml8LGXBHAVRgOY1NK/VLSgWH1Sb9pWJmLU2NuJMW8c8CLC02Ic
Nc1MaRVUGpCY3useX8p3x8uOPUNpnJpY0CQ73xtAln41rYHHTnG6iBM=
-----END CERTIFICATE-----
+# "OpenTrust Root CA G1"
+# 56 C7 71 28 D9 8C 18 D9 1B 4C FD FF BC 25 EE 91
+# 03 D4 75 8E A2 AB AD 82 6A 90 F3 45 7D 46 0E B4
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESCzkFU5fX82bWTCp59rY45nMA0GCSqGSIb3DQEBCwUA
+MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
+ZW5UcnVzdCBSb290IENBIEcxMB4XDTE0MDUyNjA4NDU1MFoXDTM4MDExNTAwMDAw
+MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
+T3BlblRydXN0IFJvb3QgQ0EgRzEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQD4eUbalsUwXopxAy1wpLuwxQjczeY1wICkES3d5oeuXT2R0odsN7faYp6b
+wiTXj/HbpqbfRm9RpnHLPhsxZ2L3EVs0J9V5ToybWL0iEA1cJwzdMOWo010hOHQX
+/uMftk87ay3bfWAfjH1MBcLrARYVmBSO0ZB3Ij/swjm4eTrwSSTilZHcYTSSjFR0
+77F9jAHiOH3BX2pfJLKOYheteSCtqx234LSWSE9mQxAGFiQD4eCcjsZGT44ameGP
+uY4zbGneWK2gDqdkVBFpRGZPTBKnjix9xNRbxQA0MMHZmf4yzgeEtE7NCv82TWLx
+p2NX5Ntqp66/K7nJ5rInieV+mhxNaMbBGN4zK1FGSxyO9z0M+Yo0FMT7MzUj8czx
+Kselu7Cizv5Ta01BG2Yospb6p64KTrk5M0ScdMGTHPjgniQlQ/GbI4Kq3ywgsNw2
+TgOzfALU5nsaqocTvz6hdLubDuHAk5/XpGbKuxs74zD0M1mKB3IDVedzagMxbm+W
+G+Oin6+Sx+31QrclTDsTBM8clq8cIqPQqwWyTBIjUtz9GVsnnB47ev1CI9sjgBPw
+vFEVVJSmdz7QdFG9URQIOTfLHzSpMJ1ShC5VkLG631UAC9hWLbFJSXKAqWLXwPYY
+EQRVzXR7z2FwefR7LFxckvzluFqrTJOVoSfupb7PcSNCupt2LQIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUl0YhVyE1
+2jZVx/PxN3DlCPaTKbYwHwYDVR0jBBgwFoAUl0YhVyE12jZVx/PxN3DlCPaTKbYw
+DQYJKoZIhvcNAQELBQADggIBAB3dAmB84DWn5ph76kTOZ0BP8pNuZtQ5iSas000E
+PLuHIT839HEl2ku6q5aCgZG27dmxpGWX4m9kWaSW7mDKHyP7Rbr/jyTwyqkxf3kf
+gLMtMrpkZ2CvuVnN35pJ06iCsfmYlIrM4LvgBBuZYLFGZdwIorJGnkSI6pN+VxbS
+FXJfLkur1J1juONI5f6ELlgKn0Md/rcYkoZDSw6cMoYsYPXpSOqV7XAp8dUv/TW0
+V8/bhUiZucJvbI/NeJWsZCj9VrDDb8O+WVLhX4SPgPL0DTatdrOjteFkdjpY3H1P
+XlZs5VVZV6Xf8YpmMIzUUmI4d7S+KNfKNsSbBfD4Fdvb8e80nR14SohWZ25g/4/I
+i+GOvUKpMwpZQhISKvqxnUOOBZuZ2mKtVzazHbYNeS2WuOvyDEsMpZTGMKcmGS3t
+TAZQMPH9WD25SxdfGbRqhFS0OE85og2WaMMolP3tLR9Ka0OWLpABEPs4poEL0L91
+09S5zvE/bw4cHjdx5RiHdRk/ULlepEU0rbDK5uUTdg8xFKmOLZTW1YVNcxVPS/Ky
+Pu1svf0OnWZzsD2097+o4BGkxK51CUpjAEggpsadCwmKtODmzj7HPiY46SvepghJ
+AwSQiumPv+i2tCqjI40cHLI5kqiPAlxAOXXUc0ECd97N4EOH1uS6SsNsEn/+KuYj
+1oxx
+-----END CERTIFICATE-----
+# "OpenTrust Root CA G2"
+# 27 99 58 29 FE 6A 75 15 C1 BF E8 48 F9 C4 76 1D
+# B1 6C 22 59 29 25 7B F4 0D 08 94 F2 9E A8 BA F2
+-----BEGIN CERTIFICATE-----
+MIIFbzCCA1egAwIBAgISESChaRu/vbm9UpaPI+hIvyYRMA0GCSqGSIb3DQEBDQUA
+MEAxCzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9w
+ZW5UcnVzdCBSb290IENBIEcyMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAw
+MFowQDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwU
+T3BlblRydXN0IFJvb3QgQ0EgRzIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQDMtlelM5QQgTJT32F+D3Y5z1zCU3UdSXqWON2ic2rxb95eolq5cSG+Ntmh
+/LzubKh8NBpxGuga2F8ORAbtp+Dz0mEL4DKiltE48MLaARf85KxP6O6JHnSrT78e
+CbY2albz4e6WiWYkBuTNQjpK3eCasMSCRbP+yatcfD7J6xcvDH1urqWPyKwlCm/6
+1UWY0jUJ9gNDlP7ZvyCVeYCYitmJNbtRG6Q3ffyZO6v/v6wNj0OxmXsWEH4db0fE
+FY8ElggGQgT4hNYdvJGmQr5J1WqIP7wtUdGejeBSzFfdNTVY27SPJIjki9/ca1TS
+gSuyzpJLHB9G+h3Ykst2Z7UJmQnlrBcUVXDGPKBWCgOz3GIZ38i1MH/1PCZ1Eb3X
+G7OHngevZXHloM8apwkQHZOJZlvoPGIytbU6bumFAYueQ4xncyhZW+vj3CzMpSZy
+YhK05pyDRPZRpOLAeiRXyg6lPzq1O4vldu5w5pLeFlwoW5cZJ5L+epJUzpM5ChaH
+vGOz9bGTXOBut9Dq+WIyiET7vycotjCVXRIouZW+j1MY5aIYFuJWpLIsEPUdN6b4
+t/bQWVyJ98LVtZR00dX+G7bw5tYee9I8y6jj9RjzIR9u701oBnstXW5DiabA+aC/
+gh7PU3+06yzbXfZqfUAkBXKJOAGTy3HCOV0GEfZvePg3DTmEJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUajn6QiL3
+5okATV59M4PLuG53hq8wHwYDVR0jBBgwFoAUajn6QiL35okATV59M4PLuG53hq8w
+DQYJKoZIhvcNAQENBQADggIBAJjLq0A85TMCl38th6aP1F5Kr7ge57tx+4BkJamz
+Gj5oXScmp7oq4fBXgwpkTx4idBvpkF/wrM//T2h6OKQQbA2xx6R3gBi2oihEdqc0
+nXGEL8pZ0keImUEiyTCYYW49qKgFbdEfwFFEVn8nNQLdXpgKQuswv42hm1GqO+qT
+RmTFAHneIWv2V6CG1wZy7HBGS4tz3aAhdT7cHcCP009zHIXZ/n9iyJVvttN7jLpT
+wm+bREx50B1ws9efAvSyB7DH5fitIw6mVskpEndI2S9G/Tvw/HRwkqWOOAgfZDC2
+t0v7NqwQjqBSM2OdAzVWxWm9xiNaJ5T2pBL4LTM8oValX9YZ6e18CL13zSdkzJTa
+TkZQh+D5wVOAHrut+0dSixv9ovneDiK3PTNZbNTe9ZUGMg1RGUFcPk8G97krgCf2
+o6p6fAbhQ8MTOWIaNr3gKC6UAuQpLmBVrkA9sHSSXvAgZJY/X0VdiLWK2gKgW0VU
+3jg9CcCoSmVGFvyqv1ROTVu+OEO3KMqLM6oaJbolXCkvW0pujOotnCr2BXbgd5eA
+iN1nE28daCSLT7d0geX0YJ96Vdc+N9oWaz53rK4YcJUIeSkDiv7BO7M/Gg+kO14f
+WKGVyasvc0rQLW6aWQ9VGHgtPFGml4vmu7JwqkwR3v98KzfUetF3NI/n+UL3PIEM
+S1IK
+-----END CERTIFICATE-----
+# "OpenTrust Root CA G3"
+# B7 C3 62 31 70 6E 81 07 8C 36 7C B8 96 19 8F 1E
+# 32 08 DD 92 69 49 DD 8F 57 09 A4 10 F7 5B 62 92
+-----BEGIN CERTIFICATE-----
+MIICITCCAaagAwIBAgISESDm+Ez8JLC+BUCs2oMbNGA/MAoGCCqGSM49BAMDMEAx
+CzAJBgNVBAYTAkZSMRIwEAYDVQQKDAlPcGVuVHJ1c3QxHTAbBgNVBAMMFE9wZW5U
+cnVzdCBSb290IENBIEczMB4XDTE0MDUyNjAwMDAwMFoXDTM4MDExNTAwMDAwMFow
+QDELMAkGA1UEBhMCRlIxEjAQBgNVBAoMCU9wZW5UcnVzdDEdMBsGA1UEAwwUT3Bl
+blRydXN0IFJvb3QgQ0EgRzMwdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARK7liuTcpm
+3gY6oxH84Bjwbhy6LTAMidnW7ptzg6kjFYwvWYpa3RTqnVkrQ7cG7DK2uu5Bta1d
+oYXM6h0UZqNnfkbilPPntlahFVmhTzeXuSIevRHr9LIfXsMUmuXZl5mjYzBhMA4G
+A1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBRHd8MUi2I5
+DMlv4VBN0BBY3JWIbTAfBgNVHSMEGDAWgBRHd8MUi2I5DMlv4VBN0BBY3JWIbTAK
+BggqhkjOPQQDAwNpADBmAjEAj6jcnboMBBf6Fek9LykBl7+BFjNAk2z8+e2AcG+q
+j9uEwov1NcoG3GRvaBbhj5G5AjEA2Euly8LQCGzpGPta3U1fJAuwACEl74+nBCZx
+4nxp5V2a+EEfOzmTk51V6s2N8fvB
+-----END CERTIFICATE-----
+# "QuoVadis Root CA 1 G3"
+# 8A 86 6F D1 B2 76 B5 7E 57 8E 92 1C 65 82 8A 2B
+# ED 58 E9 F2 F2 88 05 41 34 B7 F1 F4 BF C9 CC 74
-----BEGIN CERTIFICATE-----
MIIFYDCCA0igAwIBAgIUeFhfLq0sGUvjNwc1NBMotZbUZZMwDQYJKoZIhvcNAQEL
BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
@@ -2522,37 +3216,9 @@ ZgKAvQU6O0ec7AAmTPWIUb+oI38YB7AL7YsmoWTTYUrrXJ/es69nA7Mf3W1daWhp
q1467HxpvMc7hU6eFbm0FU/DlXpY18ls6Wy58yljXrQs8C097Vpl4KlbQMJImYFt
nh8GKjwStIsPm6Ik8KaN1nrgS7ZklmOVhMJKzRwuJIczYOXD
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL
-BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
-BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00
-MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
-aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf
-qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW
-n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym
-c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+
-O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1
-o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j
-IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq
-IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz
-8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh
-vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l
-7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG
-cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD
-ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
-AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC
-roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga
-W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n
-lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE
-+V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV
-csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd
-dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg
-KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM
-HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4
-WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M
------END CERTIFICATE-----
+# "QuoVadis Root CA 2"
+# 85 A0 DD 7D D7 20 AD B7 FF 05 F8 3D 54 2B 20 9D
+# C7 FF 45 28 F7 D6 77 B1 83 89 FE A5 E5 C4 9E 86
-----BEGIN CERTIFICATE-----
MIIFtzCCA5+gAwIBAgICBQkwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
@@ -2586,37 +3252,43 @@ ohEUGW6yhhtoPkg3Goi3XZZenMfvJ2II4pEZXNLxId26F0KCl3GBUzGpn/Z9Yr9y
4aOTHcyKJloJONDO1w2AFrR4pTqHTI2KpdVGl/IsELm8VCLAAVBpQ570su9t+Oza
8eOx79+Rj1QqCyXBJhnEUhAFZdWCEOrCMc0u
-----END CERTIFICATE-----
+# "QuoVadis Root CA 2 G3"
+# 8F E4 FB 0A F9 3A 4D 0D 67 DB 0B EB B2 3E 37 C7
+# 1B F3 25 DC BC DD 24 0E A0 4D AF 58 B4 7E 18 40
-----BEGIN CERTIFICATE-----
-MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL
+MIIFYDCCA0igAwIBAgIURFc0JFuBiZs18s64KztbpybwdSgwDQYJKoZIhvcNAQEL
BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
-BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00
-MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
-aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG
-SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR
-/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu
-FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR
-U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c
-ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR
-FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k
-A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw
-eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl
-sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp
-VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q
-A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+
-ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
-BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD
-ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
-KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI
-FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv
-oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg
-u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP
-0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf
-3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl
-8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+
-DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN
-PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/
-ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0
+BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMiBHMzAeFw0xMjAxMTIxODU5MzJaFw00
+MjAxMTIxODU5MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDIgRzMwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQChriWyARjcV4g/Ruv5r+LrI3HimtFhZiFf
+qq8nUeVuGxbULX1QsFN3vXg6YOJkApt8hpvWGo6t/x8Vf9WVHhLL5hSEBMHfNrMW
+n4rjyduYNM7YMxcoRvynyfDStNVNCXJJ+fKH46nafaF9a7I6JaltUkSs+L5u+9ym
+c5GQYaYDFCDy54ejiK2toIz/pgslUiXnFgHVy7g1gQyjO/Dh4fxaXc6AcW34Sas+
+O7q414AB+6XrW7PFXmAqMaCvN+ggOp+oMiwMzAkd056OXbxMmO7FGmh77FOm6RQ1
+o9/NgJ8MSPsc9PG/Srj61YxxSscfrf5BmrODXfKEVu+lV0POKa2Mq1W/xPtbAd0j
+IaFYAI7D0GoT7RPjEiuA3GfmlbLNHiJuKvhB1PLKFAeNilUSxmn1uIZoL1NesNKq
+IcGY5jDjZ1XHm26sGahVpkUG0CM62+tlXSoREfA7T8pt9DTEceT/AFr2XK4jYIVz
+8eQQsSWu1ZK7E8EM4DnatDlXtas1qnIhO4M15zHfeiFuuDIIfR0ykRVKYnLP43eh
+vNURG3YBZwjgQQvD6xVu+KQZ2aKrr+InUlYrAoosFCT5v0ICvybIxo/gbjh9Uy3l
+7ZizlWNof/k19N+IxWA1ksB8aRxhlRbQ694Lrz4EEEVlWFA4r0jyWbYW8jwNkALG
+cC4BrTwV1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQU7edvdlq/YOxJW8ald7tyFnGbxD0wDQYJKoZIhvcNAQELBQAD
+ggIBAJHfgD9DCX5xwvfrs4iP4VGyvD11+ShdyLyZm3tdquXK4Qr36LLTn91nMX66
+AarHakE7kNQIXLJgapDwyM4DYvmL7ftuKtwGTTwpD4kWilhMSA/ohGHqPHKmd+RC
+roijQ1h5fq7KpVMNqT1wvSAZYaRsOPxDMuHBR//47PERIjKWnML2W2mWeyAMQ0Ga
+W/ZZGYjeVYg3UQt4XAoeo0L9x52ID8DyeAIkVJOviYeIyUqAHerQbj5hLja7NQ4n
+lv1mNDthcnPxFlxHBlRJAHpYErAK74X9sbgzdWqTHBLmYF5vHX/JHyPLhGGfHoJE
++V+tYlUkmlKY7VHnoX6XOuYvHxHaU4AshZ6rNRDbIl9qxV6XU/IyAgkwo1jwDQHV
+csaxfGl7w/U2Rcxhbl5MlMVerugOXou/983g7aEOGzPuVBj+D77vfoRrQ+NwmNtd
+dbINWQeFFSM51vHfqSYP1kjHs6Yi9TM3WpVHn3u6GBVv/9YUZINJ0gpnIdsPNWNg
+KCLjsZWDzYWm3S8P52dSbrsvhXz1SnPnxT7AvSESBT/8twNJAlvIJebiVDj1eYeM
+HVOyToV7BjjHLPj4sHKNJeV3UvQDHEimUF+IIDBu8oJDqz2XhOdT+yHBTw8imoa4
+WSr2Rz0ZiC3oheGe7IUIarFsNMkd7EgrO3jtZsSOeWmD3n+M
-----END CERTIFICATE-----
+# "QuoVadis Root CA 3"
+# 18 F1 FC 7F 20 5D F8 AD DD EB 7F E0 07 DD 57 E3
+# AF 37 5A 9C 4D 8D 73 54 6B F4 F1 FE D1 E1 8D 35
-----BEGIN CERTIFICATE-----
MIIGnTCCBIWgAwIBAgICBcYwDQYJKoZIhvcNAQEFBQAwRTELMAkGA1UEBhMCQk0x
GTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxGzAZBgNVBAMTElF1b1ZhZGlzIFJv
@@ -2655,6 +3327,43 @@ Wy10QJLZYxkNc91pvGJHvOB0K7Lrfb5BG7XARsWhIstfTsEokt4YutUqKLsRixeT
mJlglFwjz1onl14LBQaTNx47aTbrqZ5hHY8y2o4M1nQ+ewkk2gF3R8Q7zTSMmfXK
4SVhM7JZG+Ju1zdXtg2pEto=
-----END CERTIFICATE-----
+# "QuoVadis Root CA 3 G3"
+# 88 EF 81 DE 20 2E B0 18 45 2E 43 F8 64 72 5C EA
+# 5F BD 1F C2 D9 D2 05 73 07 09 C5 D8 B8 69 0F 46
+-----BEGIN CERTIFICATE-----
+MIIFYDCCA0igAwIBAgIULvWbAiin23r/1aOp7r0DoM8Sah0wDQYJKoZIhvcNAQEL
+BQAwSDELMAkGA1UEBhMCQk0xGTAXBgNVBAoTEFF1b1ZhZGlzIExpbWl0ZWQxHjAc
+BgNVBAMTFVF1b1ZhZGlzIFJvb3QgQ0EgMyBHMzAeFw0xMjAxMTIyMDI2MzJaFw00
+MjAxMTIyMDI2MzJaMEgxCzAJBgNVBAYTAkJNMRkwFwYDVQQKExBRdW9WYWRpcyBM
+aW1pdGVkMR4wHAYDVQQDExVRdW9WYWRpcyBSb290IENBIDMgRzMwggIiMA0GCSqG
+SIb3DQEBAQUAA4ICDwAwggIKAoICAQCzyw4QZ47qFJenMioKVjZ/aEzHs286IxSR
+/xl/pcqs7rN2nXrpixurazHb+gtTTK/FpRp5PIpM/6zfJd5O2YIyC0TeytuMrKNu
+FoM7pmRLMon7FhY4futD4tN0SsJiCnMK3UmzV9KwCoWdcTzeo8vAMvMBOSBDGzXR
+U7Ox7sWTaYI+FrUoRqHe6okJ7UO4BUaKhvVZR74bbwEhELn9qdIoyhA5CcoTNs+c
+ra1AdHkrAj80//ogaX3T7mH1urPnMNA3I4ZyYUUpSFlob3emLoG+B01vr87ERROR
+FHAGjx+f+IdpsQ7vw4kZ6+ocYfx6bIrc1gMLnia6Et3UVDmrJqMz6nWB2i3ND0/k
+A9HvFZcba5DFApCTZgIhsUfei5pKgLlVj7WiL8DWM2fafsSntARE60f75li59wzw
+eyuxwHApw0BiLTtIadwjPEjrewl5qW3aqDCYz4ByA4imW0aucnl8CAMhZa634Ryl
+sSqiMd5mBPfAdOhx3v89WcyWJhKLhZVXGqtrdQtEPREoPHtht+KPZ0/l7DxMYIBp
+VzgeAVuNVejH38DMdyM0SXV89pgR6y3e7UEuFAUCf+D+IOs15xGsIs5XPd7JMG0Q
+A4XN8f+MFrXBsj6IbGB/kE+V9/YtrQE5BwT6dYB9v0lQ7e/JxHwc64B+27bQ3RP+
+ydOc17KXqQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB
+BjAdBgNVHQ4EFgQUxhfQvKjqAkPyGwaZXSuQILnXnOQwDQYJKoZIhvcNAQELBQAD
+ggIBADRh2Va1EodVTd2jNTFGu6QHcrxfYWLopfsLN7E8trP6KZ1/AvWkyaiTt3px
+KGmPc+FSkNrVvjrlt3ZqVoAh313m6Tqe5T72omnHKgqwGEfcIHB9UqM+WXzBusnI
+FUBhynLWcKzSt/Ac5IYp8M7vaGPQtSCKFWGafoaYtMnCdvvMujAWzKNhxnQT5Wvv
+oxXqA/4Ti2Tk08HS6IT7SdEQTXlm66r99I0xHnAUrdzeZxNMgRVhvLfZkXdxGYFg
+u/BYpbWcC/ePIlUnwEsBbTuZDdQdm2NnL9DuDcpmvJRPpq3t/O5jrFc/ZSXPsoaP
+0Aj/uHYUbt7lJ+yreLVTubY/6CD50qi+YUbKh4yE8/nxoGibIh6BJpsQBJFxwAYf
+3KDTuVan45gtf4Od34wrnDKOMpTwATwiKp9Dwi7DmDkHOHv8XgBCH/MyJnmDhPbl
+8MFREsALHgQjDFSlTC9JxUrRtm5gDWv8a4uFJGS3iQ6rJUdbPM9+Sb3H6QrG2vd+
+DhcI00iX0HGS8A85PjRqHH3Y8iKuu2n0M7SmSFXRDw4m6Oy2Cy2nhTXN/VnIn9HN
+PlopNLk9hM6xZdRZkZFWdSHBd575euFgndOtBBj0fOtek49TSiIp+EgrPk2GrFt/
+ywaZWWDYWGWVjUTR939+J399roD1B0y2PpxxVJkES/1Y+Zj0
+-----END CERTIFICATE-----
+# "QuoVadis Root Certification Authority"
+# A4 5E DE 3B BB F0 9C 8A E1 5C 72 EF C0 72 68 D6
+# 93 A2 1C 99 6F D5 1E 67 CA 07 94 60 FD 6D 88 73
-----BEGIN CERTIFICATE-----
MIIF0DCCBLigAwIBAgIEOrZQizANBgkqhkiG9w0BAQUFADB/MQswCQYDVQQGEwJC
TTEZMBcGA1UEChMQUXVvVmFkaXMgTGltaXRlZDElMCMGA1UECxMcUm9vdCBDZXJ0
@@ -2689,6 +3398,9 @@ mQM6isxUJTkxgXsTIlG6Rmyhu576BGxJJnSP0nPrzDCi5upZIof4l/UO/erMkqQW
xFIY6iHOsfHmhIHluqmGKPJDWl0Snawe2ajlCmqnf6CHKc/yiU3U7MXi5nrQNiOK
SnQ2+Q==
-----END CERTIFICATE-----
+# "Secure Global CA"
+# 42 00 F5 04 3A C8 59 0E BB 52 7D 20 9E D1 50 30
+# 29 FB CB D4 1C A1 B5 06 EC 27 F1 5A DE 7D AC 69
-----BEGIN CERTIFICATE-----
MIIDvDCCAqSgAwIBAgIQB1YipOjUiolN9BPI8PjqpTANBgkqhkiG9w0BAQUFADBK
MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
@@ -2711,6 +3423,9 @@ I50mD1hp/Ed+stCNi5O/KU9DaXR2Z0vPB4zmAve14bRDtUstFJ/53CYNv6ZHdAbY
iNE6KTCEztI5gGIbqMdXSbxqVVFnFUq+NQfk1XWYN3kwFNspnWzFacxHVaIw98xc
f8LDmBxrThaA63p4ZUWiABqvDA1VZDRIuJK58bRQKfJPIx/abKwfROHdI3hRW8cW
-----END CERTIFICATE-----
+# "SecureTrust CA"
+# F1 C1 B5 0A E5 A2 0D D8 03 0E C9 F6 BC 24 82 3D
+# D3 67 B5 25 57 59 B4 E7 1B 61 FC E9 F7 37 5D 73
-----BEGIN CERTIFICATE-----
MIIDuDCCAqCgAwIBAgIQDPCOXAgWpa1Cf/DrJxhZ0DANBgkqhkiG9w0BAQUFADBI
MQswCQYDVQQGEwJVUzEgMB4GA1UEChMXU2VjdXJlVHJ1c3QgQ29ycG9yYXRpb24x
@@ -2733,6 +3448,9 @@ D5kuCLDv/WnPmRoJjeOnnyvJNjR7JLN4TJUXpAYmHrZkUjZfYGfZnMUFdAvnZyPS
CPyI6a6Lf+Ew9Dd+/cYy2i2eRDAwbO4H3tI0/NL/QPZL9GZGBlSm8jIKYyYwa5vR
3ItHuuG51WLQoqD0ZwV4KWMabwTW+MZMo5qxN7SN5ShLHZ4swrhovO0C7jE=
-----END CERTIFICATE-----
+# "Security Communication EV RootCA1"
+# A2 2D BA 68 1E 97 37 6E 2D 39 7D 72 8A AE 3A 9B
+# 62 96 B9 FD BA 60 BC 2E 11 F6 47 F2 C6 75 FB 37
-----BEGIN CERTIFICATE-----
MIIDfTCCAmWgAwIBAgIBADANBgkqhkiG9w0BAQUFADBgMQswCQYDVQQGEwJKUDEl
MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEqMCgGA1UECxMh
@@ -2754,6 +3472,9 @@ EJrbvXZ5B3eZKK2aXtqxT0QsNY6llsf9g/BYxnnWmHyojf6GPgcWkuF75x3sM3Z+
Qi5KhfmRiWiEA4Glm5q+4zfFVKtWOxgtQaQM+ELbmaDgcm+7XeEWT1MKZPlO9L9O
VL14bIjqv5wTJMJwaaJ/D8g8rQjJsJhAoyrniIPtd490
-----END CERTIFICATE-----
+# "Security Communication RootCA1"
+# E7 5E 72 ED 9F 56 0E EC 6E B4 80 00 73 A4 3F C3
+# AD 19 19 5A 39 22 82 01 78 95 97 4A 99 02 6B 6C
-----BEGIN CERTIFICATE-----
MIIDWjCCAkKgAwIBAgIBADANBgkqhkiG9w0BAQUFADBQMQswCQYDVQQGEwJKUDEY
MBYGA1UEChMPU0VDT00gVHJ1c3QubmV0MScwJQYDVQQLEx5TZWN1cml0eSBDb21t
@@ -2774,6 +3495,9 @@ Bw+SUEmK3TGXX8npN6o7WWWXlDLJs58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJU
JRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ6rBK+1YWc26sTfcioU+tHXot
RSflMMFe8toTyyVCUZVHA4xsIcx0Qu1T/zOLjw9XARYvz6buyXAiFL39vmwLAw==
-----END CERTIFICATE-----
+# "Security Communication RootCA2"
+# 51 3B 2C EC B8 10 D4 CD E5 DD 85 39 1A DF C6 C2
+# DD 60 D8 7B B7 36 D2 B5 21 48 4A A4 7A 0E BE F6
-----BEGIN CERTIFICATE-----
MIIDdzCCAl+gAwIBAgIBADANBgkqhkiG9w0BAQsFADBdMQswCQYDVQQGEwJKUDEl
MCMGA1UEChMcU0VDT00gVHJ1c3QgU3lzdGVtcyBDTy4sTFRELjEnMCUGA1UECxMe
@@ -2795,6 +3519,9 @@ t/2jioSgrGK+KwmHNPBqAbubKVY8/gA3zyNs8U6qtnRGEmyR7jTV7JqR50S+kDFy
1UkC9gLl9B/rfNmWVan/7Ir5mUf/NVoCqgTLiluHcSmRvaS0eg29mvVXIwAHIRc/
SjnRBUkLp7Y3gaVdjKozXoEofKd9J+sAro03
-----END CERTIFICATE-----
+# "Sonera Class2 CA"
+# 79 08 B4 03 14 C1 38 10 0B 51 8D 07 35 80 7F FB
+# FC F8 51 8A 00 95 33 71 05 BA 38 6B 15 3D D9 27
-----BEGIN CERTIFICATE-----
MIIDIDCCAgigAwIBAgIBHTANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEP
MA0GA1UEChMGU29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MyIENBMB4XDTAx
@@ -2814,6 +3541,121 @@ FNr450kkkdAdavphOe9r5yF1BgfYErQhIHBCcYHaPJo2vqZbDWpsmh+Re/n570K6
Tk6ezAyNlNzZRZxe7EJQY670XcSxEtzKO6gunRRaBXW37Ndj4ro1tgQIkejanZz2
ZrUYrAqmVCY0M9IbwdR/GjqOC6oybtv8TyWf2TLHllpwrN9M
-----END CERTIFICATE-----
+# "SSL.com EV Root Certification Authority ECC"
+# 22 A2 C1 F7 BD ED 70 4C C1 E7 01 B5 F4 08 C3 10
+# 88 0F E9 56 B5 DE 2A 4A 44 F9 9C 87 3A 25 A7 C8
+-----BEGIN CERTIFICATE-----
+MIIClDCCAhqgAwIBAgIILCmcWxbtBZUwCgYIKoZIzj0EAwIwfzELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xNDAyBgNVBAMMK1NTTC5jb20gRVYgUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNTIzWhcNNDEwMjEyMTgx
+NTIzWjB/MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjE0MDIGA1UEAwwrU1NMLmNv
+bSBFViBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49
+AgEGBSuBBAAiA2IABKoSR5CYG/vvw0AHgyBO8TCCogbR8pKGYfL2IWjKAMTH6kMA
+VIbc/R/fALhBYlzccBYy3h+Z1MzFB8gIH2EWB1E9fVwHU+M1OIzfzZ/ZLg1Kthku
+WnBaBu2+8KGwytAJKaNjMGEwHQYDVR0OBBYEFFvKXuXe0oGqzagtZFG22XKbl+ZP
+MA8GA1UdEwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUW8pe5d7SgarNqC1kUbbZcpuX
+5k8wDgYDVR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2gAMGUCMQCK5kCJN+vp1RPZ
+ytRrJPOwPYdGWBrssd9v+1a6cGvHOMzosYxPD/fxZ3YOg9AeUY8CMD32IygmTMZg
+h5Mmm7I1HrrW9zzRHM76JTymGoEVW/MSD2zuZYrJh6j5B+BimoxcSg==
+-----END CERTIFICATE-----
+# "SSL.com EV Root Certification Authority RSA R2"
+# 2E 7B F1 6C C2 24 85 A7 BB E2 AA 86 96 75 07 61
+# B0 AE 39 BE 3B 2F E9 D0 CC 6D 4E F7 34 91 42 5C
+-----BEGIN CERTIFICATE-----
+MIIF6zCCA9OgAwIBAgIIVrYpzTS8ePYwDQYJKoZIhvcNAQELBQAwgYIxCzAJBgNV
+BAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4GA1UEBwwHSG91c3RvbjEYMBYGA1UE
+CgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQDDC5TU0wuY29tIEVWIFJvb3QgQ2Vy
+dGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIyMB4XDTE3MDUzMTE4MTQzN1oXDTQy
+MDUzMDE4MTQzN1owgYIxCzAJBgNVBAYTAlVTMQ4wDAYDVQQIDAVUZXhhczEQMA4G
+A1UEBwwHSG91c3RvbjEYMBYGA1UECgwPU1NMIENvcnBvcmF0aW9uMTcwNQYDVQQD
+DC5TU0wuY29tIEVWIFJvb3QgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUlNBIFIy
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAjzZlQOHWTcDXtOlG2mvq
+M0fNTPl9fb69LT3w23jhhqXZuglXaO1XPqDQCEGD5yhBJB/jchXQARr7XnAjssuf
+OePPxU7Gkm0mxnu7s9onnQqG6YE3Bf7wcXHswxzpY6IXFJ3vG2fThVUCAtZJycxa
+4bH3bzKfydQ7iEGonL3Lq9ttewkfokxykNorCPzPPFTOZw+oz12WGQvE43LrrdF9
+HSfvkusQv1vrO6/PgN3B0pYEW3p+pKk8OHakYo6gOV7qd89dAFmPZiw+B6KjBSYR
+aZfqhbcPlgtLyEDhULouisv3D5oi53+aNxPN8k0TayHRwMwi8qFG9kRpnMphNQcA
+b9ZhCBHqurj26bNg5U257J8UZslXWNvNh2n4ioYSA0e/ZhN2rHd9NCSFg83XqpyQ
+Gp8hLH94t2S42Oim9HizVcuE0jLEeK6jj2HdzghTreyI/BXkmg3mnxp3zkyPuBQV
+PWKchjgGAGYS5Fl2WlPAApiiECtoRHuOec4zSnaqW4EWG7WK2NAAe15itAnWhmMO
+pgWVSbooi4iTsjQc2KRVbrcc0N6ZVTsj9CLg+SlmJuwgUHfbSguPvuUCYHBBXtSu
+UDkiFCbLsjtzdFVHB3mBOagwE0TlBIqulhMlQg+5U8Sb/M3kHN48+qvWBkofZ6aY
+MBzdLNvcGJVXZsb/XItW9XcCAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAfBgNV
+HSMEGDAWgBT5YLvU49U09rj1BoAlp3PbRmmonjAdBgNVHQ4EFgQU+WC71OPVNPa4
+9QaAJadz20ZpqJ4wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEBCwUAA4ICAQBW
+s47LCp1Jjr+kxJG7ZhcFUZh1++VQLHqe8RT6q9OKPv+RKY9ji9i0qVQBDb6Thi/5
+Sm3HXvVX+cpVHBK+Rw82xd9qt9t1wkclf7nxY/hoLVUE0fKNsKTPvDxeH3jnpaAg
+cLAExbf3cqfeIg29MyVGjGSSJuM+LmOW2puMPfgYCdcDzH2GguDKBAdRUNf/ktUM
+79qGn5nX67evaOI5JpS6aLe/g9Pqemc9YmeuJeVy6OLk7K4S9ksrPJ/psEDzOFSz
+/bdoyNrGj1E8svuR3Bznm53htw1yj+KkxKl4+esUrMZDBcJlOSgYAsOCsp0FvmXt
+ll9ldDz7CTUue5wT/RsPXcdtgTpWD8w74a8CLyKsRspGPKAcTNZEtF4uXBVmCeEm
+Kf7GUmG6sXP/wwyc5WxqlD8UykAWlYTzWamsX0xhk23RO8yilQwipmdnRC652dKK
+QbNmC1r7fSOl8hqw/96bg5Qu0T/fkreRrwU7ZcegbLHNYhLDkBvjJc40vG93drEQ
+w/cFGsDWr3RiSBd3kmmQYRzelYB0VI8YHMPzA9C/pEN1hlMYegouCRw2n5H9gooi
+S9EOUCXdywMMF8mDAAhONU2Ki+3wApRmLER/y5UnlhetCTCstnEXbosX9hwJ1C07
+mKVx01QT2WDz9UtmT/rx7iASjbSsV7FFY6GsdqnC+w==
+-----END CERTIFICATE-----
+# "SSL.com Root Certification Authority ECC"
+# 34 17 BB 06 CC 60 07 DA 1B 96 1C 92 0B 8A B4 CE
+# 3F AD 82 0E 4A A3 0B 9A CB C4 A7 4E BD CE BC 65
+-----BEGIN CERTIFICATE-----
+MIICjTCCAhSgAwIBAgIIdebfy8FoW6gwCgYIKoZIzj0EAwIwfDELMAkGA1UEBhMC
+VVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQKDA9T
+U0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZpY2F0
+aW9uIEF1dGhvcml0eSBFQ0MwHhcNMTYwMjEyMTgxNDAzWhcNNDEwMjEyMTgxNDAz
+WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hvdXN0
+b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNvbSBS
+b290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IEVDQzB2MBAGByqGSM49AgEGBSuB
+BAAiA2IABEVuqVDEpiM2nl8ojRfLliJkP9x6jh3MCLOicSS6jkm5BBtHllirLZXI
+7Z4INcgn64mMU1jrYor+8FsPazFSY0E7ic3s7LaNGdM0B9y7xgZ/wkWV7Mt/qCPg
+CemB+vNH06NjMGEwHQYDVR0OBBYEFILRhXMw5zUE044CkvvlpNHEIejNMA8GA1Ud
+EwEB/wQFMAMBAf8wHwYDVR0jBBgwFoAUgtGFczDnNQTTjgKS++Wk0cQh6M0wDgYD
+VR0PAQH/BAQDAgGGMAoGCCqGSM49BAMCA2cAMGQCMG/n61kRpGDPYbCWe+0F+S8T
+kdzt5fxQaxFGRrMcIQBiu77D5+jNB5n5DQtdcj7EqgIwH7y6C+IwJPt8bYBVCpk+
+gA0z5Wajs6O7pdWLjwkspl1+4vAHCGht0nxpbl/f5Wpl
+-----END CERTIFICATE-----
+# "SSL.com Root Certification Authority RSA"
+# 85 66 6A 56 2E E0 BE 5C E9 25 C1 D8 89 0A 6F 76
+# A8 7E C1 6D 4D 7D 5F 29 EA 74 19 CF 20 12 3B 69
+-----BEGIN CERTIFICATE-----
+MIIF3TCCA8WgAwIBAgIIeyyb0xaAMpkwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE
+BhMCVVMxDjAMBgNVBAgMBVRleGFzMRAwDgYDVQQHDAdIb3VzdG9uMRgwFgYDVQQK
+DA9TU0wgQ29ycG9yYXRpb24xMTAvBgNVBAMMKFNTTC5jb20gUm9vdCBDZXJ0aWZp
+Y2F0aW9uIEF1dGhvcml0eSBSU0EwHhcNMTYwMjEyMTczOTM5WhcNNDEwMjEyMTcz
+OTM5WjB8MQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVGV4YXMxEDAOBgNVBAcMB0hv
+dXN0b24xGDAWBgNVBAoMD1NTTCBDb3Jwb3JhdGlvbjExMC8GA1UEAwwoU1NMLmNv
+bSBSb290IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFJTQTCCAiIwDQYJKoZIhvcN
+AQEBBQADggIPADCCAgoCggIBAPkP3aMrfcvQKv7sZ4Wm5y4bunfh4/WvpOz6Sl2R
+xFdHaxh3a3by/ZPkPQ/CFp4LZsNWlJ4Xg4XOVu/yFv0AYvUiCVToZRdOQbngT0aX
+qhvIuG5iXmmxX9sqAn78bMrzQdjt0Oj8P2FI7bADFB0QDksZ4LtO7IZl/zbzXmcC
+C52GVWH9ejjt/uIZALdvoVBidXQ8oPrIJZK0bnoix/geoeOy3ZExqysdBP+lSgQ3
+6YWkMyv94tZVNHwZpEpox7Ko07fKoZOI68GXvIz5HdkihCR0xwQ9aqkpk8zruFvh
+/l8lqjRYyMEjVJ0bmBHDOJx+PYZspQ9AhnwC9FwCTyjLrnGfDzrIM/4RJTXq/LrF
+YD3ZfBjVsqnTdXgDciLKOsMf7yzlLqn6niy2UUb9rwPW6mBo6oUWNmuF6R7As93E
+JNyAKoFBbZQ+yODJgUEAnl6/f8UImKIYLEJAs/lvOCdLToD0PYFH4Ih86hzOtXVc
+US4cK38acijnALXRdMbX5J+tB5O2UzU1/Dfkw/ZdFr4hc96SCvigY2q8lpJqPvi8
+ZVWb3vUNiSYE/CUapiVpy8JtynziWV+XrOvvLsi81xtZPCvM8hnIk2snYxnP/Okm
++Mpxm3+T/jRnhE6Z6/yzeAkzcLpmpnbtG3PrGqUNxCITIJRWCk4sbE6x/c+cCbqi
+M+2HAgMBAAGjYzBhMB0GA1UdDgQWBBTdBAkHovV6fVJTEpKV7jiAJQ2mWTAPBgNV
+HRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFN0ECQei9Xp9UlMSkpXuOIAlDaZZMA4G
+A1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAIBgRlCn7Jp0cHh5wYfGV
+cpNxJK1ok1iOMq8bs3AD/CUrdIWQPXhq9LmLpZc7tRiRux6n+UBbkflVma8eEdBc
+Hadm47GUBwwyOabqG7B52B2ccETjit3E+ZUfijhDPwGFpUenPUayvOUiaPd7nNgs
+PgohyC0zrL/FgZkxdMF1ccW+sfAjRfSda/wZY52jvATGGAslu1OJD7OAUN5F7kR/
+q5R4ZJjT9ijdh9hwZXT7DrkT66cPYakylszeu+1jTBi7qUD3oFRuIIhxdRjqerQ0
+cuAjJ3dctpDqhiVAq+8zD8ufgr6iIPv2tS0a5sKFsXQP+8hlAqRSAUfdSSLBv9jr
+a6x+3uxjMxW3IwiPxg+NQVrdjsW5j+VFP3jbutIbQLH+cU0/4IGiul607BXgk90I
+H37hVZkLId6Tngr75qNJvTYw/ud3sqB1l7UtgYgXZSD32pAAn8lSzDLKNXz1PQ/Y
+K9f1JmzJBjSWFupwWRoyeXkLtoh/D1JIPb9s2KJELtFOt3JY04kTlf5Eq/jXixtu
+nLwsoFvVagCvXzfh1foQC5ichucmj87w7G6KVwuA406ywKBjYZC6VWg3dGq2ktuf
+oYYitmUnDuy2n0Jg5GfCtdpBC8TTi2EbvPofkSvXRAdeuims2cXp71NIWuuA8ShY
+Ic2wBlX7Jz9TkHCpBB5XJ7k=
+-----END CERTIFICATE-----
+# "Staat der Nederlanden EV Root CA"
+# 4D 24 91 41 4C FE 95 67 46 EC 4C EF A6 CF 6F 72
+# E2 8A 13 29 43 2F 9D 8A 90 7A C4 CB 5D AD C1 5A
-----BEGIN CERTIFICATE-----
MIIFcDCCA1igAwIBAgIEAJiWjTANBgkqhkiG9w0BAQsFADBYMQswCQYDVQQGEwJO
TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSkwJwYDVQQDDCBTdGFh
@@ -2846,6 +3688,9 @@ eG9QgkRQP2YGiqtDhFZKDyAthg710tvSeopLzaXoTvFeJiUBWSOgftL2fiFX1ye8
FVdMpEbB4IMeDExNH08GGeL5qPQ6gqGyeUN51q1veieQA6TqJIc/2b3Z6fJfUEkc
7uzXLg==
-----END CERTIFICATE-----
+# "Staat der Nederlanden Root CA - G2"
+# 66 8C 83 94 7D A6 3B 72 4B EC E1 74 3C 31 A0 E6
+# AE D0 DB 8E C5 B3 1B E3 77 BB 78 4F 91 B6 71 6F
-----BEGIN CERTIFICATE-----
MIIFyjCCA7KgAwIBAgIEAJiWjDANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
@@ -2879,6 +3724,9 @@ N1trSt8sV4pAWja63XVECDdCcAz+3F4hoKOKwJCcaNpQ5kUQR3i2TtJlycM33+FC
Y7BXN0Ute4qcvwXqZVUz9zkQxSgqIXobisQk+T8VyJoVIPVVYpbtbZNQvOSqeK3Z
ywplh6ZmwcSBo3c6WB4L7oOLnR7SUqTMHW+wmG2UMbX4cQrcufx9MmDm66+KAQ==
-----END CERTIFICATE-----
+# "Staat der Nederlanden Root CA - G3"
+# 3C 4F B0 B9 5A B8 B3 00 32 F4 32 B8 6F 53 5F E1
+# 72 C1 85 D0 FD 39 86 58 37 CF 36 18 7F A6 F4 28
-----BEGIN CERTIFICATE-----
MIIFdDCCA1ygAwIBAgIEAJiiOTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJO
TDEeMBwGA1UECgwVU3RhYXQgZGVyIE5lZGVybGFuZGVuMSswKQYDVQQDDCJTdGFh
@@ -2911,6 +3759,9 @@ fsbAddJu+2gw7OyLnflJNZoaLNmzlTnVHpL3prllL+U9bTpITAjc5CgSKL59NVzq
QFH1T/U67cjF68IeHRaVesd+QnGTbksVtzDfqu1XhUisHWrdOWnk4Xl4vs4Fv6EM
94B7IWcnMFk=
-----END CERTIFICATE-----
+# "Starfield Class 2 Certification Authority"
+# 14 65 FA 20 53 97 B8 76 FA A6 F0 A9 95 8E 55 90
+# E4 0F CC 7F AA 4F B7 C2 C8 67 75 21 FB 5F B6 58
-----BEGIN CERTIFICATE-----
MIIEDzCCAvegAwIBAgIBADANBgkqhkiG9w0BAQUFADBoMQswCQYDVQQGEwJVUzEl
MCMGA1UEChMcU3RhcmZpZWxkIFRlY2hub2xvZ2llcywgSW5jLjEyMDAGA1UECxMp
@@ -2935,6 +3786,9 @@ xy16paq8U4Zt3VekyvggQQto8PT7dL5WXXp59fkdheMtlb71cZBDzI0fmgAKhynp
VSJYACPq4xJDKVtHCN2MQWplBqjlIapBtJUhlbl90TSrE9atvNziPTnNvT51cKEY
WQPJIrSPnNVeKtelttQKbfi3QBFGmh95DmK/D5fs4C8fF5Q=
-----END CERTIFICATE-----
+# "Starfield Root Certificate Authority - G2"
+# 2C E1 CB 0B F9 D2 F9 E1 02 99 3F BE 21 51 52 C3
+# B2 DD 0C AB DE 1C 68 E5 31 9B 83 91 54 DB B7 F5
-----BEGIN CERTIFICATE-----
MIID3TCCAsWgAwIBAgIBADANBgkqhkiG9w0BAQsFADCBjzELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
@@ -2958,6 +3812,9 @@ sHU48TRqneSfioYmUeYs0cYtbpUgSpIB7LiKZ3sx4mcujJUDJi5DnUox9g61DLu3
pL/QlwVKvOoYKAKQvVR4CSFx09F9HdkWsKlhPdAKACL8x3vLCWRFCztAgfd9fDL1
mMpYjn0q7pBZc2T5NnReJaH1ZgUufzkVqSr7UIuOhWn0
-----END CERTIFICATE-----
+# "Starfield Services Root Certificate Authority - G2"
+# 56 8D 69 05 A2 C8 87 08 A4 B3 02 51 90 ED CF ED
+# B1 97 4A 60 6A 13 C6 E5 29 0F CB 2A E6 3E DA B5
-----BEGIN CERTIFICATE-----
MIID7zCCAtegAwIBAgIBADANBgkqhkiG9w0BAQsFADCBmDELMAkGA1UEBhMCVVMx
EDAOBgNVBAgTB0FyaXpvbmExEzARBgNVBAcTClNjb3R0c2RhbGUxJTAjBgNVBAoT
@@ -2982,37 +3839,9 @@ iEDPfUYd/x7H4c7/I9vG+o1VTqkC50cRRj70/b17KSa7qWFiNyi2LSr2EIZkyXCn
0q23KXB56jzaYyWf/Wi3MOxw+3WKt21gZ7IeyLnp2KhvAotnDU0mV3HaIPzBSlCN
sSi6
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
-MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
-aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
-OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
-A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
-CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
-JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
-vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
-D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
-Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
-RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
-HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
-nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
-0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
-UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
-Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
-TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
-AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
-BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
-2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
-UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
-6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
-9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
-HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
-wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
-XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
-IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
-hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
-so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
------END CERTIFICATE-----
+# "StartCom Certification Authority"
+# C7 66 A9 BE F2 D4 07 1C 86 3A 31 AA 49 20 E8 13
+# B2 D1 98 60 8C B7 B7 CF E2 11 43 B8 36 DF 09 EA
-----BEGIN CERTIFICATE-----
MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
@@ -3057,6 +3886,9 @@ O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
-----END CERTIFICATE-----
+# "StartCom Certification Authority"
+# E1 78 90 EE 09 A3 FB F4 F4 8B 9C 41 4A 17 D6 37
+# B7 A5 06 47 E9 BC 75 23 22 72 7F CC 17 42 A9 11
-----BEGIN CERTIFICATE-----
MIIHhzCCBW+gAwIBAgIBLTANBgkqhkiG9w0BAQsFADB9MQswCQYDVQQGEwJJTDEW
MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
@@ -3100,6 +3932,43 @@ JnHEhV5xJMqlG2zYYdMa4FTbzrqpMrUi9nNBCV24F10OD5mQ1kfabwo6YigUZ4LZ
8dCAWZvLMdibD4x3TrVoivJs9iQOLWxwxXPR3hTQcY+203sC9uO41Alua551hDnm
fyWl8kgAwKQB2j8=
-----END CERTIFICATE-----
+# "StartCom Certification Authority G2"
+# C7 BA 65 67 DE 93 A7 98 AE 1F AA 79 1E 71 2D 37
+# 8F AE 1F 93 C4 39 7F EA 44 1B B7 CB E6 FD 59 95
+-----BEGIN CERTIFICATE-----
+MIIFYzCCA0ugAwIBAgIBOzANBgkqhkiG9w0BAQsFADBTMQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoGA1UEAxMjU3RhcnRDb20gQ2VydGlm
+aWNhdGlvbiBBdXRob3JpdHkgRzIwHhcNMTAwMTAxMDEwMDAxWhcNMzkxMjMxMjM1
+OTAxWjBTMQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjEsMCoG
+A1UEAxMjU3RhcnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgRzIwggIiMA0G
+CSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC2iTZbB7cgNr2Cu+EWIAOVeq8Oo1XJ
+JZlKxdBWQYeQTSFgpBSHO839sj60ZwNq7eEPS8CRhXBF4EKe3ikj1AENoBB5uNsD
+vfOpL9HG4A/LnooUCri99lZi8cVytjIl2bLzvWXFDSxu1ZJvGIsAQRSCb0AgJnoo
+D/Uefyf3lLE3PbfHkffiAez9lInhzG7TNtYKGXmu1zSCZf98Qru23QumNK9LYP5/
+Q0kGi4xDuFby2X8hQxfqp0iVAXV16iulQ5XqFYSdCI0mblWbq9zSOdIxHWDirMxW
+RST1HFSr7obdljKF+ExP6JV2tgXdNiNnvP8V4so75qbsO+wmETRIjfaAKxojAuuK
+HDp2KntWFhxyKrOq42ClAJ8Em+JvHhRYW6Vsi1g8w7pOOlz34ZYrPu8HvKTlXcxN
+nw3h3Kq74W4a7I/htkxNeXJdFzULHdfBR9qWJODQcqhaX2YtENwvKhOuJv4KHBnM
+0D4LnMgJLvlblnpHnOl68wVQdJVznjAJ85eCXuaPOQgeWeU1FEIT/wCc976qUM/i
+UUjXuG+v+E5+M5iSFGI6dWPPe/regjupuznixL0sAA7IF6wT700ljtizkC+p2il9
+Ha90OrInwMEePnWjFqmveiJdnxMaz6eg6+OGCtP95paV1yPIN93EfKo2rJgaErHg
+TuixO/XWb/Ew1wIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQE
+AwIBBjAdBgNVHQ4EFgQUS8W0QGutHLOlHGVuRjaJhwUMDrYwDQYJKoZIhvcNAQEL
+BQADggIBAHNXPyzVlTJ+N9uWkusZXn5T50HsEbZH77Xe7XRcxfGOSeD8bpkTzZ+K
+2s06Ctg6Wgk/XzTQLwPSZh0avZyQN8gMjgdalEVGKua+etqhqaRpEpKwfTbURIfX
+UfEpY9Z1zRbkJ4kd+MIySP3bmdCPX1R0zKxnNBFi2QwKN4fRoxdIjtIXHfbX/dtl
+6/2o1PXWT6RbdejF0mCy2wl+JYt7ulKSnj7oxXehPOBKc2thz4bcQ///If4jXSRK
+9dNtD2IEBVeC2m6kMyV5Sy5UGYvMLD0w6dEG/+gyRr61M3Z3qAFdlsHB1b6uJcDJ
+HgoJIIihDsnzb02CVAAgp9KP5DlUFy6NHrgbuxu9mk47EDTcnIhT76IxW1hPkWLI
+wpqazRVdOKnWvvgTtZ8SafJQYqz7Fzf07rh1Z2AQ+4NQ+US1dZxAF7L+/XldblhY
+XzD8AK6vM8EOTmy6p6ahfzLbOOCxchcKK5HsamMm7YnUeMx0HgX4a/6ManY5Ka5l
+IxKVCCIcl85bBu4M4ru8H0ST9tg4RQUh7eStqxK2A6RCLi3ECToDZ2mEmuFZkIoo
+hdVddLHRDiBYmxOlsGOm7XtH/UVVMKTumtTm4ofvmMkyghEpIrwACjFeLQ/Ajulr
+so8uBtjRkcfGEvRM/TAXw8HaOFvjqermobp573PYtlNXLfbQ4ddI
+-----END CERTIFICATE-----
+# "Swisscom Root CA 1"
+# 21 DB 20 12 36 60 BB 2E D4 18 20 5D A1 1E E7 A8
+# 5A 65 E2 BC 6E 55 B5 AF 7E 78 99 C8 A2 66 D9 2E
-----BEGIN CERTIFICATE-----
MIIF2TCCA8GgAwIBAgIQXAuFXAvnWUHfV8w/f52oNjANBgkqhkiG9w0BAQUFADBk
MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
@@ -3134,6 +4003,9 @@ hFZhvnEX/h0TD/7Gh0Xp/jKgGg0TpJRVcaUWi7rKibCyx/yP2FS1k2Kdzs9Z+z0Y
zirLNRWCXf9UIltxUvu3yf5gmwBBZPCqKuy2QkPOiWaByIufOVQDJdMWNY6E0F/6
MBr1mmz0DlP5OlvRHA==
-----END CERTIFICATE-----
+# "Swisscom Root CA 2"
+# F0 9B 12 2C 71 14 F4 A0 9B D4 EA 4F 4A 99 D5 58
+# B4 6E 4C 25 CD 81 14 0D 29 C0 56 13 91 4C 38 41
-----BEGIN CERTIFICATE-----
MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBk
MQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0
@@ -3168,6 +4040,9 @@ t6NlUe07qxS/TFED6F+KBZvuim6c779o+sjaC+NCydAXFJy3SuCvkychVSa1ZC+N
9CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX5OfNeOI5
wSsSnqaeG8XmDtkx2Q==
-----END CERTIFICATE-----
+# "Swisscom Root EV CA 2"
+# D9 5F EA 3C A4 EE DC E7 4C D7 6E 75 FC 6D 1F F6
+# 2C 44 1F 0F A8 BC 77 F0 34 B1 9E 5D B2 58 01 5D
-----BEGIN CERTIFICATE-----
MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAw
ZzELMAkGA1UEBhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdp
@@ -3202,6 +4077,9 @@ WkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/giuMod89a2GQ+fYWVq6nTI
fI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuWl8PVP3wb
I+2ksx0WckNLIOFZfsLorSa/ovc=
-----END CERTIFICATE-----
+# "SwissSign Gold CA - G2"
+# 62 DD 0B E9 B9 F5 0A 16 3E A0 F8 E7 5C 05 3B 1E
+# CA 57 EA 55 C8 68 8F 64 7C 68 81 F2 C8 35 7B 95
-----BEGIN CERTIFICATE-----
MIIFujCCA6KgAwIBAgIJALtAHEP1Xk+wMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxHzAdBgNVBAMTFlN3aXNzU2ln
@@ -3235,6 +4113,9 @@ Ld6leNcG2mqeSz53OiATIgHQv2ieY2BrNU0LbbqhPcCT4H8js1WtciVORvnSFu+w
ZMEBnunKoGqYDs/YYPIvSbjkQuE4NRb0yG5P94FW6LqjviOvrv1vA+ACOzB2+htt
Qc8Bsem4yWb02ybzOqR08kkkW8mw0FfB+j564ZfJ
-----END CERTIFICATE-----
+# "SwissSign Gold Root CA - G3"
+# 7A F6 EA 9F 75 3A 1E 70 9B D6 4D 0B EB 86 7C 11
+# E8 C2 95 A5 6E 24 A6 E0 47 14 59 DC CD AA 15 58
-----BEGIN CERTIFICATE-----
MIIFejCCA2KgAwIBAgIJAN7E8kTzHab8MA0GCSqGSIb3DQEBCwUAMEoxCzAJBgNV
BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJDAiBgNVBAMTG1N3aXNzU2ln
@@ -3267,6 +4148,9 @@ sD5onnKIUTidEz5FbQXlRrVz7UOGsRQKHrzaDb8eJFxmjw6+of3G62m8Q3nXA3b5
3IeZuJjEzX9tEPkQvixC/pwpTYNrCr21jsRIiv0hB6aAfR+b6au9gmFECnEnX22b
kJ6u/zYks2gD1pWMa3M=
-----END CERTIFICATE-----
+# "SwissSign Platinum CA - G2"
+# 3B 22 2E 56 67 11 E9 92 30 0D C0 B1 5A B9 47 3D
+# AF DE F8 C8 4D 0C EF 7D 33 17 B4 C1 82 1D 14 36
-----BEGIN CERTIFICATE-----
MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWdu
@@ -3300,6 +4184,9 @@ DI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSYMdp08YSTcU1f+2BY0fvEwW2JorsgH51x
kcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAciIfNAChs0B0QTwoRqjt8Z
Wr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g==
-----END CERTIFICATE-----
+# "SwissSign Platinum Root CA - G3"
+# 59 B3 82 9F 1F F4 43 34 49 58 FA E8 BF F6 21 B6
+# 84 C8 48 CF BF 7E AD 6B 63 A6 CA 50 F2 79 4F 89
-----BEGIN CERTIFICATE-----
MIIFgTCCA2mgAwIBAgIIIj+pFyDegZQwDQYJKoZIhvcNAQELBQAwTjELMAkGA1UE
BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEoMCYGA1UEAxMfU3dpc3NTaWdu
@@ -3332,6 +4219,9 @@ OWQQW5VLNV1EgyTV4C4kDMGAbmkAgAZ3CmaCEAxRbzeJV9vzTOW4ue4jZpdgt1Ld
2Zb7uoo7oE3OXvBETJDMIU8bOphrjjGD+YMIUssZwTVr7qEVW4g/bazyNJJTpjAq
E9fmhqhd2ULSx52peovL3+6iMcLl
-----END CERTIFICATE-----
+# "SwissSign Silver CA - G2"
+# BE 6C 4D A2 BB B9 BA 59 B6 F3 93 97 68 37 42 46
+# C3 C0 05 99 3F A9 8F 02 0D 1D ED BE D4 8A 81 D5
-----BEGIN CERTIFICATE-----
MIIFvTCCA6WgAwIBAgIITxvUL1S7L0swDQYJKoZIhvcNAQEFBQAwRzELMAkGA1UE
BhMCQ0gxFTATBgNVBAoTDFN3aXNzU2lnbiBBRzEhMB8GA1UEAxMYU3dpc3NTaWdu
@@ -3365,6 +4255,9 @@ OMpXEA29MC/HpeZBoNquBYeaoKRlbEwJDIm6uNO5wJOKMPqN5ZprFQFOZ6raYlY+
hAhm0sQ2fac+EPyI4NSA5QC9qvNOBqN6avlicuMJT+ubDgEj8Z+7fNzcbBGXJbLy
tGMU0gYqZ4yD9c7qB9iaah7s5Aq7KkzrCWA5zspi2C5u
-----END CERTIFICATE-----
+# "SwissSign Silver Root CA - G3"
+# 1E 49 AC 5D C6 9E 86 D0 56 5D A2 C1 30 5C 41 93
+# 30 B0 B7 81 BF EC 50 E5 4A 1B 35 AF 7F DD D5 01
-----BEGIN CERTIFICATE-----
MIIFfjCCA2agAwIBAgIJAKqIsFoLsXabMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
BAYTAkNIMRUwEwYDVQQKEwxTd2lzc1NpZ24gQUcxJjAkBgNVBAMTHVN3aXNzU2ln
@@ -3397,23 +4290,9 @@ BzuGaUWpxzaWkHJ02BKmcyPRTrm2ejrEKaFQBhG52fQmbmIIEiAW8AFXF9QFNmeX
61H5/zMkDAUPVr/vPRxSjoreaQ9aH/DVAzFEs5LG6nWorrvHYAOImP/HBIRSkIbh
tJOpUC/o69I2rDBgp9ADE7UK
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICqDCCAi2gAwIBAgIQIW4zpcvTiKRvKQe0JzzE2DAKBggqhkjOPQQDAzCBlDEL
-MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
-VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
-bGFzcyAxIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
-RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
-bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAxIFB1
-YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
-hkjOPQIBBgUrgQQAIgNiAATXZrUb266zYO5G6ohjdTsqlG3zXxL24w+etgoUU0hS
-yNw6s8tIICYSTvqJhNTfkeQpfSgB2dsYQ2mhH7XThhbcx39nI9/fMTGDAzVwsUu3
-yBe7UcvclBfb6gk7dhLeqrWjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBRlwI0l9Qy6l3eQP54u4Fr1ztXh5DAKBggqhkjOPQQD
-AwNpADBmAjEApa7jRlP4mDbjIvouKEkN7jB+M/PsP3FezFWJeJmssv3cHFwzjim5
-axfIEWi13IMHAjEAnMhE2mnCNsNUGRCFAtqdR+9B52wmnQk9922Q0QVEL7C8g5No
-8gxFSTm/mQQc0xCg
------END CERTIFICATE-----
+# "Symantec Class 1 Public Primary Certification Authority - G6"
+# 9D 19 0B 2E 31 45 66 68 5B E8 A8 89 E2 7A A8 C7
+# D7 AE 1D 8A AD DB A3 C1 EC F9 D2 48 63 CD 34 B9
-----BEGIN CERTIFICATE-----
MIID9jCCAt6gAwIBAgIQJDJ18h0v0gkz97RqytDzmDANBgkqhkiG9w0BAQsFADCB
lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
@@ -3438,23 +4317,9 @@ dPTXvQbKqDqNVkL6jXI+dPEDct+HG14OelWWLDi3mIXNTTNEyZSPWjEwN0ujOhKz
DJqXPDe/v+z28LSFdyjBC8hnghAXOKK3Buqbvzr46SMHv3TgmDgVVXjucgBcGaP0
0jPg/73RVDkpDw==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICqDCCAi2gAwIBAgIQNBdlEkA7t1aALYDLeVWmHjAKBggqhkjOPQQDAzCBlDEL
-MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
-VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
-bGFzcyAyIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
-RzQwHhcNMTExMDA1MDAwMDAwWhcNMzgwMTE4MjM1OTU5WjCBlDELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
-bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAyIFB1
-YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
-hkjOPQIBBgUrgQQAIgNiAATR2UqOTA2ESlG6fO/TzPo6mrWnYxM9AeBJPvrBR8mS
-szrX/m+c95o6D/UOCgrDP8jnEhSO1dVtmCyzcTIK6yq99tdqIAtnRZzSsr9TImYJ
-XdsR8/EFM1ij4rjPfM2Cm72jQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBQ9MvM6qQyQhPmijGkGYVQvh3L+BTAKBggqhkjOPQQD
-AwNpADBmAjEAyKapr0F/tckRQhZoaUxcuCcYtpjxwH+QbYfTjEYX8D5P/OqwCMR6
-S7wIL8fip29lAjEA1lnehs5fDspU1cbQFQ78i5Ry1I4AWFPPfrFLDeVQhuuea9//
-KabYR9mglhjb8kWz
------END CERTIFICATE-----
+# "Symantec Class 2 Public Primary Certification Authority - G6"
+# CB 62 7D 18 B5 8A D5 6D DE 33 1A 30 45 6B C6 5C
+# 60 1A 4E 9B 18 DE DC EA 08 E7 DA AA 07 81 5F F0
-----BEGIN CERTIFICATE-----
MIID9jCCAt6gAwIBAgIQZIKe/DcedF38l/+XyLH/QTANBgkqhkiG9w0BAQsFADCB
lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
@@ -3479,57 +4344,9 @@ Sc2lo4xpeSWuuExsi0BmSxY/zwIa3eFsawdhanYVKZl/G92IgMG/tY9zxaaWI4Sm
KIYkM2oBLldzJbZev4/mHWGoQClnHYebHX+bn5nNMdZUvmK7OaxoEkiRIKXLsd3+
b/xa5IJVWa8xqQ==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIICpzCCAi2gAwIBAgIQTHm1miicdjFk9YlE0JEC3jAKBggqhkjOPQQDAzCBlDEL
-MAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYD
-VQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBD
-bGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0g
-RzQwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UEBhMC
-VVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZTeW1h
-bnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAzIFB1
-YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzQwdjAQBgcq
-hkjOPQIBBgUrgQQAIgNiAARXz+qzOU0/oSHgbi84csaHl/OFC0fnD1HI0fSZm8pZ
-Zf9M+eoLtyXV0vbsMS0yYhLXdoan+jjJZdT+c+KEOfhMSWIT3brViKBfPchPsD+P
-oVAR5JNGrcNfy/GkapVW6MCjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
-BTADAQH/MB0GA1UdDgQWBBQknbzScfcdwiW+IvGJpSwVOzQeXjAKBggqhkjOPQQD
-AwNoADBlAjEAuWZoZdsF0Dh9DvPIdWG40CjEsUozUVj78jwQyK5HeHbKZiQXhj5Q
-Vm6lLZmIuL0kAjAD6qfnqDzqnWLGX1TamPR3vU+PGJyRXEdrQE0QHbPhicoLIsga
-xcX+i93B3294n5E=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIF9jCCA96gAwIBAgIQZWNxhdNvRcaPfzH5CYeSgjANBgkqhkiG9w0BAQwFADCB
-lDELMAkGA1UEBhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8w
-HQYDVQQLExZTeW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRl
-YyBDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5
-IC0gRzYwHhcNMTIxMDE4MDAwMDAwWhcNMzcxMjAxMjM1OTU5WjCBlDELMAkGA1UE
-BhMCVVMxHTAbBgNVBAoTFFN5bWFudGVjIENvcnBvcmF0aW9uMR8wHQYDVQQLExZT
-eW1hbnRlYyBUcnVzdCBOZXR3b3JrMUUwQwYDVQQDEzxTeW1hbnRlYyBDbGFzcyAz
-IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzYwggIi
-MA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQC3DrL6TbyachX7d1vb/UMPywv3
-YC6zK34Mu1PyzE5l8xm7/zUd99Opu0Attd141Kb5N+qFBXttt+YTSwZ8+3ZjjyAd
-LTgrBIXy6LDRX01KIclq2JTqHgJQpqqQB6BHIepm+QSg5oPwxPVeluInTWHDs8GM
-IrZmoQDRVin77cF/JMo9+lqUsITDx7pDHP1kDvEo+0dZ8ibhMblE+avd+76+LDfj
-rAsY0/wBovGkCjWCR0yrvYpe3xOF/CDMSFmvr0FvyyPNypOn3dVfyGQ7/wEDoApP
-LW49hL6vyDKyUymQFfewBZoKPPa5BpDJpeFdoDuw/qi2v/WJKFckOiGGceTciotB
-VeweMCRZ0cBZuHivqlp03iWAMJjtMERvIXAc2xJTDtamKGaTLB/MTzwbgcW59nhv
-0DI6CHLbaw5GF4WU87zvvPekXo7p6bVk5bdLRRIsTDe3YEMKTXEGAJQmNXQfu3o5
-XE475rgD4seTi4QsJUlF3X8jlGAfy+nN9quX92Hn+39igcjcCjBcGHzmzu/Hbh6H
-fLPpysh7avRo/IOlDFa0urKNSgrHl5fFiDAVPRAIVBVycmczM/R8t84AJ1NlziTx
-WmTnNi/yLgLCl99y6AIeoPc9tftoYAP6M6nmEm0G4amoXU48/tnnAGWsthlNe4N/
-NEfq4RhtsYsceavnnQIDAQABo0IwQDAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/
-BAUwAwEB/zAdBgNVHQ4EFgQUOXEIAD7eyIbnkP/k/SEPziQZFvYwDQYJKoZIhvcN
-AQEMBQADggIBAFBriE1gSM5a4yLOZ3yEp80c/ekMA4w2rwqHDmquV64B0Da78v25
-c8FftaiuTKL6ScsHRhY2vePIVzh+OOS/JTNgxtw3nGO7XpgeGrKC8K6mdxGAREeh
-KcXwszrOmPC47NMOgAZ3IzBM/3lkYyJbd5NDS3Wz2ztuO0rd8ciutTeKlYg6EGhw
-OLlbcH7VQ8n8X0/l5ns27vAg7UdXEyYQXhQGDXt2B8LGLRb0rqdsD7yID08sAraj
-1yLmmUc12I2lT4ESOhF9s8wLdfMecKMbA+r6mujmLjY5zJnOOj8Mt674Q5mwk25v
-qtkPajGRu5zTtCj7g0x6c4JQZ9IOrO1gxbJdNZjPh34eWR0kvFa62qRa2MzmvB4Q
-jxuMjvPB27e+1LBbZY8WaPNWxSoZFk0PuGWHbSSDuGLc4EdhGoh7zk5//dzGDVqa
-pPO1TPbdMaboHREhMzAEYX0c4D5PjT+1ixIAWn2poQDUg+twuxj4pNIcgS23CBHI
-Jnu21OUPA0Zy1CVAHr5JXW2T8VyyO3VUaTqg7kwiuqya4gitRWMFSlI1dsQ09V4H
-Mq3cfCbRW4+t5OaqG3Wf61206MCpFXxOSgdy30bJ1JGSdVaw4e43NmUoxRXIK3bM
-bW8Zg/T92hXiQeczeUaDV/nxpbZt07zXU+fucW14qZen7iCcGRVyFT0E
------END CERTIFICATE-----
+# "SZAFIR ROOT CA"
+# FA BC F5 19 7C DD 7F 45 8A C3 38 32 D3 28 40 21
+# DB 24 25 FD 6B EA 7A 2E 69 B7 48 6E 8F 51 F9 CC
-----BEGIN CERTIFICATE-----
MIIDcTCCAlmgAwIBAgIVAOYJ/nrqAGiM4CS07SAbH+9StETRMA0GCSqGSIb3DQEB
BQUAMFAxCzAJBgNVBAYTAlBMMSgwJgYDVQQKDB9LcmFqb3dhIEl6YmEgUm96bGlj
@@ -3551,6 +4368,9 @@ lTOjkjuGXEcyQAjQzbFaT9vIABSbeCXWBbjvOXukJy6WgAiclzGNSYprre8Ryydd
fmjW9HIGwsIO03EldivvqEYL1Hv1w/Pur+6FUEOaL68PEIUovfgwIB2BAw+vZDuw
cH0mX548PojGyg434cDjkSXa3mHF
-----END CERTIFICATE-----
+# "T-TeleSec GlobalRoot Class 2"
+# 91 E2 F5 78 8D 58 10 EB A7 BA 58 73 7D E1 54 8A
+# 8E CA CD 01 45 98 BC 0B 14 3E 04 1B 17 05 25 52
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
@@ -3574,6 +4394,9 @@ g1XqfMIpiRvpb7PO4gWEyS8+eIVibslfwXhjdFjASBgMmTnrpMwatXlajRWc2BQN
9noHV8cigwUtPJslJj0Ys6lDfMjIq2SPDqO/nBudMNva0Bkuqjzx+zOAduTNrRlP
BSeOE6Fuwg==
-----END CERTIFICATE-----
+# "T-TeleSec GlobalRoot Class 3"
+# FD 73 DA D3 1C 64 4F F1 B4 3B EF 0C CD DA 96 71
+# 0B 9C D9 87 5E CA 7E 31 70 7A F3 E9 6D 52 2B BD
-----BEGIN CERTIFICATE-----
MIIDwzCCAqugAwIBAgIBATANBgkqhkiG9w0BAQsFADCBgjELMAkGA1UEBhMCREUx
KzApBgNVBAoMIlQtU3lzdGVtcyBFbnRlcnByaXNlIFNlcnZpY2VzIEdtYkgxHzAd
@@ -3597,6 +4420,9 @@ WL6ukK2YJ5f+AbGwUgC4TeQbIXQbfsDuXmkqJa9c1h3a0nnJ85cp4IaH3gRZD/FZ
e9eiPZaGzPImNC1qkp2aGtAw4l1OBLBfiyB+d8E9lYLRRpo7PHi4b6HQDWSieB4p
TpPDpFQUWw==
-----END CERTIFICATE-----
+# "TeliaSonera Root CA v1"
+# DD 69 36 FE 21 F8 F0 77 C1 23 A1 A5 21 C1 22 24
+# F7 22 55 B7 3E 03 A7 26 06 93 E8 A2 4B 0F A3 89
-----BEGIN CERTIFICATE-----
MIIFODCCAyCgAwIBAgIRAJW+FqD3LkbxezmCcvqLzZYwDQYJKoZIhvcNAQEFBQAw
NzEUMBIGA1UECgwLVGVsaWFTb25lcmExHzAdBgNVBAMMFlRlbGlhU29uZXJhIFJv
@@ -3627,22 +4453,37 @@ t88NkvuOGKmYSdGe/mBEciG5Ge3C9THxOUiIkCR1VBatzvT4aRRkOfujuLpwQMcn
HL/EVlP6Y2XQ8xwOFvVrhlhNGNTkDY6lnVuR3HYkUD/GKvvZt5y11ubQ2egZixVx
SK236thZiNSQvxaz2emsWWFUyBy6ysHK4bkgTI86k4mloMy/0/Z1pHWWbVY=
-----END CERTIFICATE-----
+# "thawte Primary Root CA"
+# 8D 72 2F 81 A9 C1 13 C0 79 1D F1 36 A2 96 6D B2
+# 6C 95 0A 97 1D B4 6B 41 99 F4 EA 54 B7 8B FB 9F
-----BEGIN CERTIFICATE-----
-MIICiDCCAg2gAwIBAgIQNfwmXNmET8k9Jj1Xm67XVjAKBggqhkjOPQQDAzCBhDEL
-MAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjE4MDYGA1UECxMvKGMp
-IDIwMDcgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxJDAi
-BgNVBAMTG3RoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EgLSBHMjAeFw0wNzExMDUwMDAw
-MDBaFw0zODAxMTgyMzU5NTlaMIGEMQswCQYDVQQGEwJVUzEVMBMGA1UEChMMdGhh
-d3RlLCBJbmMuMTgwNgYDVQQLEy8oYykgMjAwNyB0aGF3dGUsIEluYy4gLSBGb3Ig
-YXV0aG9yaXplZCB1c2Ugb25seTEkMCIGA1UEAxMbdGhhd3RlIFByaW1hcnkgUm9v
-dCBDQSAtIEcyMHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEotWcgnuVnfFSeIf+iha/
-BebfowJPDQfGAFG6DAJSLSKkQjnE/o/qycG+1E3/n3qe4rF8mq2nhglzh9HnmuN6
-papu+7qzcMBniKI11KOasf2twu8x+qi58/sIxpHR+ymVo0IwQDAPBgNVHRMBAf8E
-BTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUmtgAMADna3+FGO6Lts6K
-DPgR4bswCgYIKoZIzj0EAwMDaQAwZgIxAN344FdHW6fmCsO99YCKlzUNG4k8VIZ3
-KMqh9HneteY4sPBlcIx/AlTCv//YoT7ZzwIxAMSNlPzcU9LcnXgWHxUzI1NS41ox
-XZ3Krr0TKUQNJ1uo52icEvdYPy5yAlejj6EULg==
+MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
+qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
+Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
+MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
+BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
+NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
+LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
+A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
+IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
+SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
+W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
+3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
+6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
+Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
+NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
+MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
+r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
+DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
+YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
+xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
+/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
+LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
+jVaMaA==
-----END CERTIFICATE-----
+# "thawte Primary Root CA - G3"
+# 4B 03 F4 58 07 AD 70 F2 1B FC 2C AE 71 C9 FD E4
+# 60 4C 06 4C F5 FF B6 86 BA E5 DB AA D7 FD D3 4C
-----BEGIN CERTIFICATE-----
MIIEKjCCAxKgAwIBAgIQYAGXt0an6rS0mtZLL/eQ+zANBgkqhkiG9w0BAQsFADCB
rjELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
@@ -3668,31 +4509,9 @@ KUGRIjxpp7sC8rZcJwOJ9Abqm+RyguOhCcHpABnTPtRwa7pxpqpYrvS76Wy274fM
m7v/OeZWYdMKp8RcTGB7BXcmer/YB1IsYvdwY9k5vG8cwnncdimvzsUsZAReiDZu
MdRAGmI0Nj81Aa6sY6A=
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEIDCCAwigAwIBAgIQNE7VVyDV7exJ9C/ON9srbTANBgkqhkiG9w0BAQUFADCB
-qTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5jLjEoMCYGA1UECxMf
-Q2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYGA1UECxMvKGMpIDIw
-MDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNV
-BAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwHhcNMDYxMTE3MDAwMDAwWhcNMzYw
-NzE2MjM1OTU5WjCBqTELMAkGA1UEBhMCVVMxFTATBgNVBAoTDHRoYXd0ZSwgSW5j
-LjEoMCYGA1UECxMfQ2VydGlmaWNhdGlvbiBTZXJ2aWNlcyBEaXZpc2lvbjE4MDYG
-A1UECxMvKGMpIDIwMDYgdGhhd3RlLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl
-IG9ubHkxHzAdBgNVBAMTFnRoYXd0ZSBQcmltYXJ5IFJvb3QgQ0EwggEiMA0GCSqG
-SIb3DQEBAQUAA4IBDwAwggEKAoIBAQCsoPD7gFnUnMekz52hWXMJEEUMDSxuaPFs
-W0hoSVk3/AszGcJ3f8wQLZU0HObrTQmnHNK4yZc2AreJ1CRfBsDMRJSUjQJib+ta
-3RGNKJpchJAQeg29dGYvajig4tVUROsdB58Hum/u6f1OCyn1PoSgAfGcq/gcfomk
-6KHYcWUNo1F77rzSImANuVud37r8UVsLr5iy6S7pBOhih94ryNdOwUxkHt3Ph1i6
-Sk/KaAcdHJ1KxtUvkcx8cXIcxcBn6zL9yZJclNqFwJu/U30rCfSMnZEfl2pSy94J
-NqR32HuHUETVPm4pafs5SSYeCaWAe0At6+gnhcn+Yf1+5nyXHdWdAgMBAAGjQjBA
-MA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMB0GA1UdDgQWBBR7W0XP
-r87Lev0xkhpqtvNG61dIUDANBgkqhkiG9w0BAQUFAAOCAQEAeRHAS7ORtvzw6WfU
-DW5FvlXok9LOAz/t2iWwHVfLHjp2oEzsUHboZHIMpKnxuIvW1oeEuzLlQRHAd9mz
-YJ3rG9XRbkREqaYB7FViHXe4XI5ISXycO1cRrK1zN44veFyQaEfZYGDm/Ac9IiAX
-xPcW6cTYcvnIc3zfFi8VqT79aie2oetaupgf1eNNZAqdE8hhuvU5HIe6uL17In/2
-/qxAeeWsEG89jxt5dovEN7MhGITlNgDrYyCZuen+MwS7QcjBAvlEYyCegc5C09Y/
-LHbTY5xZ3Y+m4Q6gLkH3LpVHz7z9M/P2C2F+fpErgUfCJzDupxBdN49cOSvkBPB7
-jVaMaA==
------END CERTIFICATE-----
+# "TRUST2408 OCES Primary CA"
+# 92 D8 09 2E E7 7B C9 20 8F 08 97 DC 05 27 18 94
+# E6 3E F2 79 33 AE 53 7F B9 83 EE F0 EA E3 EE C8
-----BEGIN CERTIFICATE-----
MIIGHDCCBASgAwIBAgIES45gAzANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJE
SzESMBAGA1UEChMJVFJVU1QyNDA4MSIwIAYDVQQDExlUUlVTVDI0MDggT0NFUyBQ
@@ -3728,6 +4547,104 @@ WIVFF/Onlu5fu1NHXdqNEfzldKDUvCfii3L2iATTZyHwU9CALE+2eIA+PIaLgnM1
1oCfUnYBkQurTrihvzz9PryCVkLxiqRmBVvUz+D4N5G/wvvKDS6t6cPCS+hqM482
cbBsn0R9fFLO4El62S9eH1tqOzO20OAOK65yJIsOpSE=
-----END CERTIFICATE-----
+# "TrustCor ECA-1"
+# 5A 88 5D B1 9C 01 D9 12 C5 75 93 88 93 8C AF BB
+# DF 03 1A B2 D4 8E 91 EE 15 58 9B 42 97 1D 03 9C
+-----BEGIN CERTIFICATE-----
+MIIEIDCCAwigAwIBAgIJAISCLF8cYtBAMA0GCSqGSIb3DQEBCwUAMIGcMQswCQYD
+VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
+MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
+cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxFzAVBgNVBAMMDlRydXN0Q29y
+IEVDQS0xMB4XDTE2MDIwNDEyMzIzM1oXDTI5MTIzMTE3MjgwN1owgZwxCzAJBgNV
+BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
+IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
+dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEXMBUGA1UEAwwOVHJ1c3RDb3Ig
+RUNBLTEwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPj+ARtZ+odnbb
+3w9U73NjKYKtR8aja+3+XzP4Q1HpGjORMRegdMTUpwHmspI+ap3tDvl0mEDTPwOA
+BoJA6LHip1GnHYMma6ve+heRK9jGrB6xnhkB1Zem6g23xFUfJ3zSCNV2HykVh0A5
+3ThFEXXQmqc04L/NyFIduUd+Dbi7xgz2c1cWWn5DkR9VOsZtRASqnKmcp0yJF4Ou
+owReUoCLHhIlERnXDH19MURB6tuvsBzvgdAsxZohmz3tQjtQJvLsznFhBmIhVE5/
+wZ0+fyCMgMsq2JdiyIMzkX2woloPV+g7zPIlstR8L+xNxqE6FXrntl019fZISjZF
+ZtS6mFjBAgMBAAGjYzBhMB0GA1UdDgQWBBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAf
+BgNVHSMEGDAWgBREnkj1zG1I1KBLf/5ZJC+Dl5mahjAPBgNVHRMBAf8EBTADAQH/
+MA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAQEABT41XBVwm8nHc2Fv
+civUwo/yQ10CzsSUuZQRg2dd4mdsdXa/uwyqNsatR5Nj3B5+1t4u/ukZMjgDfxT2
+AHMsWbEhBuH7rBiVDKP/mZb3Kyeb1STMHd3BOuCYRLDE5D53sXOpZCz2HAF8P11F
+hcCF5yWPldwX8zyfGm6wyuMdKulMY/okYWLW2n62HGz1Ah3UKt1VkOsqEUc8Ll50
+soIipX1TH0XsJ5F95yIW6MBoNtjG8U+ARDL54dHRHareqKucBK+tIA5kmE2la8BI
+WJZpTdwHjFGTot+fDz2LYLSCjaoITmJF4PkL0uDgPFveXHEnJcLmA4GLEFPjx1Wi
+tJ/X5g==
+-----END CERTIFICATE-----
+# "TrustCor RootCert CA-1"
+# D4 0E 9C 86 CD 8F E4 68 C1 77 69 59 F4 9E A7 74
+# FA 54 86 84 B6 C4 06 F3 90 92 61 F4 DC E2 57 5C
+-----BEGIN CERTIFICATE-----
+MIIEMDCCAxigAwIBAgIJANqb7HHzA7AZMA0GCSqGSIb3DQEBCwUAMIGkMQswCQYD
+VQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEgQ2l0eTEk
+MCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYDVQQLDB5U
+cnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRydXN0Q29y
+IFJvb3RDZXJ0IENBLTEwHhcNMTYwMjA0MTIzMjE2WhcNMjkxMjMxMTcyMzE2WjCB
+pDELMAkGA1UEBhMCUEExDzANBgNVBAgMBlBhbmFtYTEUMBIGA1UEBwwLUGFuYW1h
+IENpdHkxJDAiBgNVBAoMG1RydXN0Q29yIFN5c3RlbXMgUy4gZGUgUi5MLjEnMCUG
+A1UECwweVHJ1c3RDb3IgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MR8wHQYDVQQDDBZU
+cnVzdENvciBSb290Q2VydCBDQS0xMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEAv463leLCJhJrMxnHQFgKq1mqjQCj/IDHUHuO1CAmujIS2CNUSSUQIpid
+RtLByZ5OGy4sDjjzGiVoHKZaBeYei0i/mJZ0PmnK6bV4pQa81QBeCQryJ3pS/C3V
+seq0iWEk8xoT26nPUu0MJLq5nux+AHT6k61sKZKuUbS701e/s/OojZz0JEsq1pme
+9J7+wH5COucLlVPat2gOkEz7cD+PSiyU8ybdY2mplNgQTsVHCJCZGxdNuWxu72CV
+EY4hgLW9oHPY0LJ3xEXqWib7ZnZ2+AYfYW0PVcWDtxBWcgYHpfOxGgMFZA6dWorW
+hnAbJN7+KIor0Gqw/Hqi3LJ5DotlDwIDAQABo2MwYTAdBgNVHQ4EFgQU7mtJPHo/
+DeOxCbeKyKsZn3MzUOcwHwYDVR0jBBgwFoAU7mtJPHo/DeOxCbeKyKsZn3MzUOcw
+DwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYwDQYJKoZIhvcNAQELBQAD
+ggEBACUY1JGPE+6PHh0RU9otRCkZoB5rMZ5NDp6tPVxBb5UrJKF5mDo4Nvu7Zp5I
+/5CQ7z3UuJu0h3U/IJvOcs+hVcFNZKIZBqEHMwwLKeXx6quj7LUKdJDHfXLy11yf
+ke+Ri7fc7Waiz45mO7yfOgLgJ90WmMCV1Aqk5IGadZQ1nJBfiDcGrVmVCrDRZ9MZ
+yonnMlo2HD6CqFqTvsbQZJG2z9m2GM/bftJlo6bEjhcxwft+dtvTheNYsnd6djts
+L1Ac59v2Z3kf9YKVmgenFK+P3CghZwnS1k1aHBkcjndcw5QkPTJrS37UeJSDvjdN
+zl/HHk484IkzlQsPpTLWPFp5LBk=
+-----END CERTIFICATE-----
+# "TrustCor RootCert CA-2"
+# 07 53 E9 40 37 8C 1B D5 E3 83 6E 39 5D AE A5 CB
+# 83 9E 50 46 F1 BD 0E AE 19 51 CF 10 FE C7 C9 65
+-----BEGIN CERTIFICATE-----
+MIIGLzCCBBegAwIBAgIIJaHfyjPLWQIwDQYJKoZIhvcNAQELBQAwgaQxCzAJBgNV
+BAYTAlBBMQ8wDQYDVQQIDAZQYW5hbWExFDASBgNVBAcMC1BhbmFtYSBDaXR5MSQw
+IgYDVQQKDBtUcnVzdENvciBTeXN0ZW1zIFMuIGRlIFIuTC4xJzAlBgNVBAsMHlRy
+dXN0Q29yIENlcnRpZmljYXRlIEF1dGhvcml0eTEfMB0GA1UEAwwWVHJ1c3RDb3Ig
+Um9vdENlcnQgQ0EtMjAeFw0xNjAyMDQxMjMyMjNaFw0zNDEyMzExNzI2MzlaMIGk
+MQswCQYDVQQGEwJQQTEPMA0GA1UECAwGUGFuYW1hMRQwEgYDVQQHDAtQYW5hbWEg
+Q2l0eTEkMCIGA1UECgwbVHJ1c3RDb3IgU3lzdGVtcyBTLiBkZSBSLkwuMScwJQYD
+VQQLDB5UcnVzdENvciBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkxHzAdBgNVBAMMFlRy
+dXN0Q29yIFJvb3RDZXJ0IENBLTIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIK
+AoICAQCnIG7CKqJiJJWQdsg4foDSq8GbZQWU9MEKENUCrO2fk8eHyLAnK0IMPQo+
+QVqedd2NyuCb7GgypGmSaIwLgQ5WoD4a3SwlFIIvl9NkRvRUqdw6VC0xK5mC8tkq
+1+9xALgxpL56JAfDQiDyitSSBBtlVkxs1Pu2YVpHI7TYabS3OtB0PAx1oYxOdqHp
+2yqlO/rOsP9+aij9JxzIsekp8VduZLTQwRVtDr4uDkbIXvRR/u8OYzo7cbrPb1nK
+DOObXUm4TOJXsZiKQlecdu/vvdFoqNL0Cbt3Nb4lggjEFixEIFapRBF37120Hape
+az6LMvYHL1cEksr1/p3C6eizjkxLAjHZ5DxIgif3GIJ2SDpxsROhOdUuxTTCHWKF
+3wP+TfSvPd9cW436cOGlfifHhi5qjxLGhF5DUVCcGZt45vz27Ud+ez1m7xMTiF88
+oWP7+ayHNZ/zgp6kPwqcMWmLmaSISo5uZk3vFsQPeSghYA2FFn3XVDjxklb9tTNM
+g9zXEJ9L/cb4Qr26fHMC4P99zVvh1Kxhe1fVSntb1IVYJ12/+CtgrKAmrhQhJ8Z3
+mjOAPF5GP/fDsaOGM8boXg25NSyqRsGFAnWAoOsk+xWq5Gd/bnc/9ASKL3x74xdh
+8N0JqSDIvgmk0H5Ew7IwSjiqqewYmgeCK9u4nBit2uBGF6zPXQIDAQABo2MwYTAd
+BgNVHQ4EFgQU2f4hQG6UnrybPZx9mCAZ5YwwYrIwHwYDVR0jBBgwFoAU2f4hQG6U
+nrybPZx9mCAZ5YwwYrIwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAYYw
+DQYJKoZIhvcNAQELBQADggIBAJ5Fngw7tu/hOsh80QA9z+LqBrWyOrsGS2h60COX
+dKcs8AjYeVrXWoSK2BKaG9l9XE1wxaX5q+WjiYndAfrs3fnpkpfbsEZC89NiqpX+
+MWcUaViQCqoL7jcjx1BRtPV+nuN79+TMQjItSQzL/0kMmx40/W5ulop5A7Zv2wnL
+/V9lFDfhOPXzYRZY5LVtDQsEGz9QLX+zx3oaFoBg+Iof6Rsqxvm6ARppv9JYx1RX
+CI/hOWB3S6xZhBqI8d3LT3jX5+EzLfzuQfogsL7L9ziUwOHQhQ+77Sxzq+3+knYa
+ZH9bDTMJBzN7Bj8RpFxwPIXAz+OQqIN3+tvmxYxoZxBnpVIt8MSZj3+/0WvitUfW
+2dCFmU2Umw9Lje4AWkcdEQOsQRivh7dvDDqPys/cA8GiCcjl/YBeyGBCARsaU1q7
+N6a3vLqE6R5sGtRk2tRD/pOLS/IseRYQ1JMLiI+h2IYURpFHmygk71dSTlxCnKr3
+Sewn6EAes6aJInKc9Q0ztFijMDvd1GpUk74aTfOTlPf8hAs/hCBcNANExdqtvArB
+As8e5ZTZ845b2EzwnexhF7sUMlQMAimTHpKG9n/v55IFDlndmQguLvqcAFLTxWYp
+5KeXRKQOKIETNcX2b2TmQcTVL8w0RSXPQQCWPUouwpaYT05KnJe32x+SMsj/D1Fu
+1uwJ
+-----END CERTIFICATE-----
+# "Trustis FPS Root CA"
+# C1 B4 82 99 AB A5 20 8F E9 63 0A CE 55 CA 68 A0
+# 3E DA 5A 51 9C 88 02 A0 D3 A6 73 BE 8F 8E 55 7D
-----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIQGx+ttiD5JNM2a/fH8YygWTANBgkqhkiG9w0BAQUFADBF
MQswCQYDVQQGEwJHQjEYMBYGA1UEChMPVHJ1c3RpcyBMaW1pdGVkMRwwGgYDVQQL
@@ -3749,6 +4666,38 @@ f1T1o+CP8HxVIo8ptoGj4W1OLBuAZ+ytIJ8MYmHVl/9D7S3B2l0pKoU/rGXuhg8F
jZBf3+6f9L/uHfuY5H+QK4R4EA5sSVPvFVtlRkpdr7r7OnIdzfYliB6XzCGcKQEN
ZetX2fNXlrtIzYE=
-----END CERTIFICATE-----
+# "TUBITAK Kamu SM SSL Kok Sertifikasi - Surum 1"
+# 46 ED C3 68 90 46 D5 3A 45 3F B3 10 4A B8 0D CA
+# EC 65 8B 26 60 EA 16 29 DD 7E 86 79 90 64 87 16
+-----BEGIN CERTIFICATE-----
+MIIEYzCCA0ugAwIBAgIBATANBgkqhkiG9w0BAQsFADCB0jELMAkGA1UEBhMCVFIx
+GDAWBgNVBAcTD0dlYnplIC0gS29jYWVsaTFCMEAGA1UEChM5VHVya2l5ZSBCaWxp
+bXNlbCB2ZSBUZWtub2xvamlrIEFyYXN0aXJtYSBLdXJ1bXUgLSBUVUJJVEFLMS0w
+KwYDVQQLEyRLYW11IFNlcnRpZmlrYXN5b24gTWVya2V6aSAtIEthbXUgU00xNjA0
+BgNVBAMTLVRVQklUQUsgS2FtdSBTTSBTU0wgS29rIFNlcnRpZmlrYXNpIC0gU3Vy
+dW0gMTAeFw0xMzExMjUwODI1NTVaFw00MzEwMjUwODI1NTVaMIHSMQswCQYDVQQG
+EwJUUjEYMBYGA1UEBxMPR2ViemUgLSBLb2NhZWxpMUIwQAYDVQQKEzlUdXJraXll
+IEJpbGltc2VsIHZlIFRla25vbG9qaWsgQXJhc3Rpcm1hIEt1cnVtdSAtIFRVQklU
+QUsxLTArBgNVBAsTJEthbXUgU2VydGlmaWthc3lvbiBNZXJrZXppIC0gS2FtdSBT
+TTE2MDQGA1UEAxMtVFVCSVRBSyBLYW11IFNNIFNTTCBLb2sgU2VydGlmaWthc2kg
+LSBTdXJ1bSAxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAr3UwM6q7
+a9OZLBI3hNmNe5eA027n/5tQlT6QlVZC1xl8JoSNkvoBHToP4mQ4t4y86Ij5iySr
+LqP1N+RAjhgleYN1Hzv/bKjFxlb4tO2KRKOrbEz8HdDc72i9z+SqzvBV96I01INr
+N3wcwv61A+xXzry0tcXtAA9TNypN9E8Mg/uGz8v+jE69h/mniyFXnHrfA2eJLJ2X
+YacQuFWQfw4tJzh03+f92k4S400VIgLI4OD8D62K18lUUMw7D8oWgITQUVbDjlZ/
+iSIzL+aFCr2lqBs23tPcLG07xxO9WSMs5uWk99gL7eqQQESolbuT1dCANLZGeA4f
+AJNG4e7p+exPFwIDAQABo0IwQDAdBgNVHQ4EFgQUZT/HiobGPN08VFw1+DrtUgxH
+V8gwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL
+BQADggEBACo/4fEyjq7hmFxLXs9rHmoJ0iKpEsdeV31zVmSAhHqT5Am5EM2fKifh
+AHe+SMg1qIGf5LgsyX8OsNJLN13qudULXjS99HMpw+0mFZx+CFOKWI3QSyjfwbPf
+IPP54+M638yclNhOT8NrF7f3cuitZjO1JVOr4PhMqZ398g26rrnZqsZr+ZO7rqu4
+lzwDGrpDxpa5RXI4s6ehlj2Re37AIVNMh+3yC1SVUZPVIqUNivGTDj5UDrDYyU7c
+8jEyVupk+eq1nRZmQnLzf9OxMUP8pI4X8W0jq5Rm+K37DwhuJi1/FwcJsoz7UMCf
+lo3Ptv0AnVoUmr8CRPXBwp8iXqIPoeM=
+-----END CERTIFICATE-----
+# "TWCA Global Root CA"
+# 59 76 90 07 F7 68 5D 0F CD 50 87 2F 9F 95 D5 75
+# 5A 5B 2B 45 7D 81 F3 69 2B 61 0A 98 67 2F 0E 1B
-----BEGIN CERTIFICATE-----
MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcx
EjAQBgNVBAoTCVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMT
@@ -3780,6 +4729,9 @@ wa19hAM8EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWz
aGHQRiapIVJpLesux+t3zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmy
KwbQBM0=
-----END CERTIFICATE-----
+# "TWCA Root Certification Authority"
+# BF D8 8F E1 10 1C 41 AE 3E 80 1B F8 BE 56 35 0E
+# E9 BA D1 A6 B9 BD 51 5E DC 5C 6D 5B 87 11 AC 44
-----BEGIN CERTIFICATE-----
MIIDezCCAmOgAwIBAgIBATANBgkqhkiG9w0BAQUFADBfMQswCQYDVQQGEwJUVzES
MBAGA1UECgwJVEFJV0FOLUNBMRAwDgYDVQQLDAdSb290IENBMSowKAYDVQQDDCFU
@@ -3801,61 +4753,9 @@ lhh9DrUUOYTxKOkto557HnpyWoOzeW/vtPzQCqVYT0bf+215WfKEIlKuD8z7fDvn
aspHYcN6+NOSBB+4IIThNlQWx0DeO4pz3N/GCUzf7Nr/1FNCocnyYh0igzyXxfkZ
YiesZSLX0zzG5Y6yU8xJzrww/nsOM5D77dIUkR8Hrw==
-----END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIFFzCCA/+gAwIBAgIBETANBgkqhkiG9w0BAQUFADCCASsxCzAJBgNVBAYTAlRS
-MRgwFgYDVQQHDA9HZWJ6ZSAtIEtvY2FlbGkxRzBFBgNVBAoMPlTDvHJraXllIEJp
-bGltc2VsIHZlIFRla25vbG9qaWsgQXJhxZ90xLFybWEgS3VydW11IC0gVMOcQsSw
-VEFLMUgwRgYDVQQLDD9VbHVzYWwgRWxla3Ryb25payB2ZSBLcmlwdG9sb2ppIEFy
-YcWfdMSxcm1hIEVuc3RpdMO8c8O8IC0gVUVLQUUxIzAhBgNVBAsMGkthbXUgU2Vy
-dGlmaWthc3lvbiBNZXJrZXppMUowSAYDVQQDDEFUw5xCxLBUQUsgVUVLQUUgS8O2
-ayBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsSAtIFPDvHLDvG0gMzAe
-Fw0wNzA4MjQxMTM3MDdaFw0xNzA4MjExMTM3MDdaMIIBKzELMAkGA1UEBhMCVFIx
-GDAWBgNVBAcMD0dlYnplIC0gS29jYWVsaTFHMEUGA1UECgw+VMO8cmtpeWUgQmls
-aW1zZWwgdmUgVGVrbm9sb2ppayBBcmHFn3TEsXJtYSBLdXJ1bXUgLSBUw5xCxLBU
-QUsxSDBGBgNVBAsMP1VsdXNhbCBFbGVrdHJvbmlrIHZlIEtyaXB0b2xvamkgQXJh
-xZ90xLFybWEgRW5zdGl0w7xzw7wgLSBVRUtBRTEjMCEGA1UECwwaS2FtdSBTZXJ0
-aWZpa2FzeW9uIE1lcmtlemkxSjBIBgNVBAMMQVTDnELEsFRBSyBVRUtBRSBLw7Zr
-IFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxIC0gU8O8csO8bSAzMIIB
-IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAim1L/xCIOsP2fpTo6iBkcK4h
-gb46ezzb8R1Sf1n68yJMlaCQvEhOEav7t7WNeoMojCZG2E6VQIdhn8WebYGHV2yK
-O7Rm6sxA/OOqbLLLAdsyv9Lrhc+hDVXDWzhXcLh1xnnRFDDtG1hba+818qEhTsXO
-fJlfbLm4IpNQp81McGq+agV/E5wrHur+R84EpW+sky58K5+eeROR6Oqeyjh1jmKw
-lZMq5d/pXpduIF9fhHpEORlAHLpVK/swsoHvhOPc7Jg4OQOFCKlUAwUp8MmPi+oL
-hmUZEdPpCSPeaJMDyTYcIW7OjGbxmTDY17PDHfiBLqi9ggtm/oLL4eAagsNAgQID
-AQABo0IwQDAdBgNVHQ4EFgQUvYiHyY/2pAoLquvF/pEjnatKijIwDgYDVR0PAQH/
-BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEFBQADggEBAB18+kmP
-NOm3JpIWmgV050vQbTlswyb2zrgxvMTfvCr4N5EY3ATIZJkrGG2AA1nJrvhY0D7t
-wyOfaTyGOBye79oneNGEN3GKPEs5z35FBtYt2IpNeBLWrcLTy9LQQfMmNkqblWwM
-7uXRQydmwYj3erMgbOqwaSvHIOgMA8RBBZniP+Rr+KCGgceExh/VS4ESshYhLBOh
-gLJeDEoTniDYYkCrkOpkSi+sDQESeUWoL4cZaMjihccwsnX5OD+ywJO0a+IDRM5n
-oN+J1q2MdqMTw5RhK2vZbMEHCiIHhWyFJEapvj+LeISCfiQMnf2BN+MlqO02TpUs
-yZyQ2uypQjyttgI=
------END CERTIFICATE-----
------BEGIN CERTIFICATE-----
-MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOc
-UktUUlVTVCBFbGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sx
-c8SxMQswCQYDVQQGEwJUUjEPMA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xS
-S1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUgQmlsacWfaW0gR8O8dmVubGnEn2kg
-SGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4XDTA3MTIyNTE4Mzcx
-OVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxla3Ry
-b25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMC
-VFIxDzANBgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDE
-sGxldGnFn2ltIHZlIEJpbGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7F
-ni4gKGMpIEFyYWzEsWsgMjAwNzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC
-ggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9NYvDdE3ePYakqtdTyuTFY
-KTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQvKUmi8wUG
-+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveG
-HtyaKhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6P
-IzdezKKqdfcYbwnTrqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M
-733WB2+Y8a+xwXrXgTW4qhe04MsCAwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHk
-Yb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8EBTADAQH/MA0G
-CSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/sPx+EnWVUXKgW
-AkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I
-aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5
-mxRZNTZPz/OOXl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsa
-XRik7r4EW5nVcV9VZWRi1aKbBFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZ
-qxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAKpoRq0Tl9
------END CERTIFICATE-----
+# "UCA Global Root"
+# A1 F0 5C CB 80 C2 D7 10 EC 7D 47 9A BD CB B8 79
+# E5 8D 7E DB 71 49 FE 78 A8 78 84 E3 D0 BA D0 F9
-----BEGIN CERTIFICATE-----
MIIFkjCCA3qgAwIBAgIBCDANBgkqhkiG9w0BAQUFADA6MQswCQYDVQQGEwJDTjER
MA8GA1UEChMIVW5pVHJ1c3QxGDAWBgNVBAMTD1VDQSBHbG9iYWwgUm9vdDAeFw0w
@@ -3888,6 +4788,9 @@ Ka/wI3J9FO2pXd96gZ6bkiL8HvgBRUGXx2sBYb4zaPKgZYRmvOAqpGjTcezHCN6j
w8k2SjTxF+KAryAhk5Qe5hXTVGLxtTgv48y5ZwSpuuXu+RBuyy5+E6+SFP7zJ3N7
OPxzbbm5iPZujAv1/P8JDrMtXnt145Ik4ubhWD5LKAN1axibRww=
-----END CERTIFICATE-----
+# "UCA Root"
+# 93 E6 5E C7 62 F0 55 DC 71 8A 33 25 82 C4 1A 04
+# 43 0D 72 E3 CB 87 E8 B8 97 B6 75 16 F0 D1 AA 39
-----BEGIN CERTIFICATE-----
MIIDhDCCAmygAwIBAgIBCTANBgkqhkiG9w0BAQUFADAzMQswCQYDVQQGEwJDTjER
MA8GA1UEChMIVW5pVHJ1c3QxETAPBgNVBAMTCFVDQSBSb290MB4XDTA0MDEwMTAw
@@ -3909,6 +4812,9 @@ LJzltQ7dFyiuawHTUin1Ih+QOfTcYmjwPIZH7LgFRbu3DJaUxmfLI3HQjnQi1kHr
A6i26r7EARK1s11AdgYg1GS4KUYGis4fk5oQ7vuqWrTcL9Ury/bXBYSYBZELhPc9
+tb5evosFeo2gkO3t7jj83EB7UNDogVFwygFBzXjAaU4HoDU18PZ3g==
-----END CERTIFICATE-----
+# "USERTrust ECC Certification Authority"
+# 4F F4 60 D5 4B 9C 86 DA BF BC FC 57 12 E0 40 0D
+# 2B ED 3F BC 4D 4F BD AA 86 E0 6A DC D2 A9 AD 7A
-----BEGIN CERTIFICATE-----
MIICjzCCAhWgAwIBAgIQXIuZxVqUxdJxVt7NiYDMJjAKBggqhkjOPQQDAzCBiDEL
MAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0plcnNl
@@ -3925,6 +4831,9 @@ VR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAwNoADBlAjA2Z6EWCNzklwBBHU6+4WMB
zzuqQhFkoJ2UOQIReVx7Hfpkue4WQrO/isIJxOzksU0CMQDpKmFHjFJKS04YcPbW
RNZu9YO6bVi9JNlWSOrvxKJGgYhqOkbRqZtNyWHa0V1Xahg=
-----END CERTIFICATE-----
+# "USERTrust RSA Certification Authority"
+# E7 93 C9 B0 2F D8 AA 13 E2 1C 31 22 8A CC B0 81
+# 19 64 3B 74 9C 89 89 64 B1 74 6D 46 C3 D4 CB D2
-----BEGIN CERTIFICATE-----
MIIF3jCCA8agAwIBAgIQAf1tMPyjylGoG7xkDjUDLTANBgkqhkiG9w0BAQwFADCB
iDELMAkGA1UEBhMCVVMxEzARBgNVBAgTCk5ldyBKZXJzZXkxFDASBgNVBAcTC0pl
@@ -3959,6 +4868,9 @@ VXyNWQKV3WKdwrnuWih0hKWbt5DHDAff9Yk2dDLWKMGwsAvgnEzDHNb842m1R0aB
L6KCq9NjRHDEjf8tM7qtj3u1cIiuPhnPQCjY/MiQu12ZIvVS5ljFH4gxQ+6IHdfG
jjxDah2nGN59PRbxYvnKkKj9
-----END CERTIFICATE-----
+# "UTN - DATACorp SGC"
+# 85 FB 2F 91 DD 12 27 5A 01 45 B6 36 53 4F 84 02
+# 4A D6 8B 69 B8 EE 88 68 4F F7 11 37 58 05 B3 48
-----BEGIN CERTIFICATE-----
MIIEXjCCA0agAwIBAgIQRL4Mi1AAIbQR0ypoBqmtaTANBgkqhkiG9w0BAQUFADCB
kzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -3985,6 +4897,9 @@ KWss5nbZqSl9Mt3JNjy9rjXxEZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv
2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwPDPafepE39peC4N1xaf92P2BNPM/3
mfnGV/TJVTl4uix5yaaIK/QI
-----END CERTIFICATE-----
+# "UTN-USERFirst-Client Authentication and Email"
+# 43 F2 57 41 2D 44 0D 62 74 76 97 4F 87 7D A8 F1
+# FC 24 44 56 5A 36 7A E6 0E DD C2 7A 41 25 31 AE
-----BEGIN CERTIFICATE-----
MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCB
rjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -4012,6 +4927,9 @@ rfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarVNZ1yQAOJujEdxRBoUp7fooXFXAim
eOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZw7JHpsIyYdfHb0gk
USeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ=
-----END CERTIFICATE-----
+# "UTN-USERFirst-Hardware"
+# 6E A5 47 41 D0 04 66 7E ED 1B 48 16 63 4A A3 A7
+# 9E 6E 4B 96 95 0F 82 79 DA FC 8D 9B D8 81 21 37
-----BEGIN CERTIFICATE-----
MIIEdDCCA1ygAwIBAgIQRL4Mi1AAJLQR0zYq/mUK/TANBgkqhkiG9w0BAQUFADCB
lzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -4038,6 +4956,9 @@ CJChicsZUN/KHAG8HQQZexB2lzvukJDKxA4fFm517zP4029bHpbj4HR3dHuKom4t
3XbWOTCC8KucUvIqx69JXn7HaOWCgchqJ/kniCrVWFCVH/A7HFe7fRQ5YiuayZSS
KqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67nfhmqA==
-----END CERTIFICATE-----
+# "UTN-USERFirst-Object"
+# 6F FF 78 E4 00 A7 0C 11 01 1C D8 59 77 C4 59 FB
+# 5A F9 6A 3D F0 54 08 20 D0 F4 B8 60 78 75 E5 8F
-----BEGIN CERTIFICATE-----
MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCB
lTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2Ug
@@ -4064,6 +4985,9 @@ mMiKVl0+7kNOPmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU
81OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCGhU3IfdeLA/5u1fedFqySLKAj5ZyR
Uh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g=
-----END CERTIFICATE-----
+# "VeriSign Class 1 Public Primary Certification Authority - G3"
+# CB B5 AF 18 5E 94 2A 24 02 F9 EA CB C0 ED 5B B8
+# 76 EE A3 C1 22 36 23 D0 04 47 E4 F3 BA 55 4B 65
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
@@ -4088,6 +5012,9 @@ ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrs
pSCAaWihT37ha88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4
E1Z5T21Q6huwtVexN2ZYI/PcD98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g==
-----END CERTIFICATE-----
+# "VeriSign Class 2 Public Primary Certification Authority - G3"
+# 92 A9 D9 83 3F E1 94 4D B3 66 E8 BF AE 7A 95 B6
+# 48 0C 2D 6C 6C 2A 1B E6 5D 42 36 B6 08 FC A1 BB
-----BEGIN CERTIFICATE-----
MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJ
BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVy
@@ -4112,6 +5039,9 @@ sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RI
sH/7NiXaldDxJBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTP
cjnhsUPgKM+351psE2tJs//jGHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q
-----END CERTIFICATE-----
+# "VeriSign Class 3 Public Primary Certification Authority - G3"
+# EB 04 CF 5E B1 F3 9A FA 76 2F 2B B1 20 F2 96 CB
+# A5 20 C1 B9 7D B1 58 95 65 B8 1C B9 A1 7B 72 44
-----BEGIN CERTIFICATE-----
MIIEGjCCAwICEQCbfgZJoz5iudXukEhxKe9XMA0GCSqGSIb3DQEBBQUAMIHKMQsw
CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZl
@@ -4136,6 +5066,9 @@ DGBvtcC1IyIuBwvLqXTLR7sdwdela8wv0kL9Sd2nic9TutoAWii/gt/4uhMdUIaC
F4ErWjfJXir0xuKhXFSbplQAz/DxwceYMBo7Nhbbo27q/a2ywtrvAkcTisDxszGt
TxzhT5yvDwyd93gN2PQ1VoDat20Xj50egWTh/sVFuq1ruQp6Tk9LhO5L8X3dEQ==
-----END CERTIFICATE-----
+# "VeriSign Class 3 Public Primary Certification Authority - G4"
+# 69 DD D7 EA 90 BB 57 C9 3E 13 5D C8 5E A6 FC D5
+# 48 0B 60 32 39 BD C4 54 FC 75 8B 2A 26 CF 7F 79
-----BEGIN CERTIFICATE-----
MIIDhDCCAwqgAwIBAgIQL4D+I4wOIg9IZxIokYesszAKBggqhkjOPQQDAzCByjEL
MAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZW
@@ -4157,6 +5090,9 @@ kf3upm7ktS5Jj4d4gYDs5bG1MAoGCCqGSM49BAMDA2gAMGUCMGYhDBgmYFo4e1ZC
4Kf8NoRRkSAsdk1DPcQdhCPQrNZ8NQbOzWm9kA3bbEhCHQ6qQgIxAJw9SDkjOVga
FRJZap7v1VmyHVIsmXHNxynfGyphe3HR3vPA5Q06Sqotp9iGKt0uEA==
-----END CERTIFICATE-----
+# "VeriSign Class 3 Public Primary Certification Authority - G5"
+# 9A CF AB 7E 43 C8 D8 80 D0 6B 26 2A 94 DE EE E4
+# B4 65 99 89 C3 D0 CA F1 9B AF 64 05 E4 1A B7 DF
-----BEGIN CERTIFICATE-----
MIIE0zCCA7ugAwIBAgIQGNrRniZ96LtKIVjNzGs7SjANBgkqhkiG9w0BAQUFADCB
yjELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
@@ -4185,6 +5121,9 @@ WE9gyn6CagsCqiUXObXbf+eEZSqVir2G3l6BFoMtEMze/aiCKm0oHw0LxOXnGiYZ
4fQRbxC1lfznQgUy286dUV4otp6F01vvpX1FQHKOtw5rDgb7MzVIcbidJ4vEZV8N
hnacRHr2lVz2XTIIM6RUthg/aFzyQkqFOFSDX9HoLPKsEdao7WNq
-----END CERTIFICATE-----
+# "VeriSign Universal Root Certification Authority"
+# 23 99 56 11 27 A5 71 25 DE 8C EF EA 61 0D DF 2F
+# A0 78 B5 C8 06 7F 4E 82 82 90 BF B8 60 E8 4B 3C
-----BEGIN CERTIFICATE-----
MIIEuTCCA6GgAwIBAgIQQBrEZCGzEyEDDrvkEhrFHTANBgkqhkiG9w0BAQsFADCB
vTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQL
@@ -4213,6 +5152,9 @@ BxHw1dvd5Yzw1TKwg+ZX4o+/vqGqvz0dtdQ46tewXDpPaj+PwGZsY6rp2aQW9IHR
lRQOfc2VNNnSj3BzgXucfr2YYdhFh5iQxeuGMMY1v/D/w1WIg0vvBZIGcfK4mJO3
7M2CYfE45k+XmCpajQ==
-----END CERTIFICATE-----
+# "Visa eCommerce Root"
+# 69 FA C9 BD 55 FB 0A C7 8D 53 BB EE 5C F1 D5 97
+# 98 9F D0 AA AB 20 A2 51 51 BD F1 73 3E E7 D1 22
-----BEGIN CERTIFICATE-----
MIIDojCCAoqgAwIBAgIQE4Y1TR0/BvLB+WUF1ZAcYjANBgkqhkiG9w0BAQUFADBr
MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
@@ -4235,6 +5177,9 @@ LBfQdCVp9/5rPJS+TUtBjE7ic9DjkCJzQ83z7+pzzkWKsKZJ/0x9nXGIxHYdkFsd
++DbZqMAAb3mLNqRX6BGi01qnD093QVG/na/oAo85ADmJ7f/hC3euiInlhBx6yLt
398znM/jra6O1I7mT1GvFpLgXPYHDw==
-----END CERTIFICATE-----
+# "Visa Information Delivery Root CA"
+# C5 7A 3A CB E8 C0 6B A1 98 8A 83 48 5B F3 26 F2
+# 44 87 75 37 98 49 DE 01 CA 43 57 1A F3 57 E7 4B
-----BEGIN CERTIFICATE-----
MIID+TCCAuGgAwIBAgIQW1fXqEywr9nTb0ugMbTW4jANBgkqhkiG9w0BAQUFADB5
MQswCQYDVQQGEwJVUzENMAsGA1UEChMEVklTQTEvMC0GA1UECxMmVmlzYSBJbnRl
@@ -4259,6 +5204,9 @@ PqZr+pfgFhwCCLSMQWl5Ll3u7Qk9wR094DZ6jj6+JCVCRUS3HyabH4OlM0Vc2K+j
INsF/64Or7GNtRf9HYEJvrPxHINxl3JVwhYj4ASeaO4KwhVbwtw94Tc/XrGcexDo
c5lC3rAi4/UZqweYCw==
-----END CERTIFICATE-----
+# "VRK Gov. Root CA"
+# F0 08 73 3E C5 00 DC 49 87 63 CC 92 64 C6 FC EA
+# 40 EC 22 00 0E 92 7D 05 3C E9 C9 0B FA 04 6C B2
-----BEGIN CERTIFICATE-----
MIIEGjCCAwKgAwIBAgIDAYagMA0GCSqGSIb3DQEBBQUAMIGjMQswCQYDVQQGEwJG
STEQMA4GA1UECBMHRmlubGFuZDEhMB8GA1UEChMYVmFlc3RvcmVraXN0ZXJpa2Vz
@@ -4283,6 +5231,9 @@ t08pLWKfT6HAVVdWDsRol5EfnGTCKTIB6dTI2riBmCguGMcs/OubUpbf9MiQGS0j
eBmK3QOjFKU3p7UsfLYRh+cF8ry23tT/l4EohP7+bEaFEEGfTXWMB9SZZ291im/k
UJL2mdUQuMSpe/cXjUu/15WfCdxEDx4yw8DP03kN5Mc7h/CQNIghYkmSBAQfvA==
-----END CERTIFICATE-----
+# "XRamp Global Certification Authority"
+# CE CD DC 90 50 99 D8 DA DF C5 B1 D2 09 B7 37 CB
+# E2 C1 8C FB 2C 10 C0 FF 0B CF 0D 32 86 FC 1A A2
-----BEGIN CERTIFICATE-----
MIIEMDCCAxigAwIBAgIQUJRs7Bjq1ZxN1ZfvdY+grTANBgkqhkiG9w0BAQUFADCB
gjELMAkGA1UEBhMCVVMxHjAcBgNVBAsTFXd3dy54cmFtcHNlY3VyaXR5LmNvbTEk
diff --git a/src/crypto/x509/root_darwin_ios_gen.go b/src/crypto/x509/root_darwin_ios_gen.go
new file mode 100644
index 0000000000..7a42466e5f
--- /dev/null
+++ b/src/crypto/x509/root_darwin_ios_gen.go
@@ -0,0 +1,179 @@
+// 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 ignore
+
+// Generates root_darwin_ios.go.
+//
+// As of iOS 13, there is no API for querying the system trusted X.509 root
+// certificates.
+//
+// Apple publishes the trusted root certificates for iOS and macOS on
+// opensource.apple.com so we embed them into the x509 package.
+//
+// Note that this ignores distrusted and revoked certificates.
+package main
+
+import (
+ "archive/tar"
+ "bytes"
+ "compress/gzip"
+ "crypto/sha256"
+ "crypto/tls"
+ "crypto/x509"
+ "encoding/pem"
+ "flag"
+ "fmt"
+ "go/format"
+ "io"
+ "io/ioutil"
+ "log"
+ "net/http"
+ "path"
+ "sort"
+ "strings"
+ "time"
+)
+
+func main() {
+ var output = flag.String("output", "root_darwin_ios.go", "file name to write")
+ var version = flag.String("version", "", "security_certificates version")
+ flag.Parse()
+ if *version == "" {
+ log.Fatal("Select the latest security_certificates version from " +
+ "https://opensource.apple.com/source/security_certificates/")
+ }
+
+ url := "https://opensource.apple.com/tarballs/security_certificates/security_certificates-%s.tar.gz"
+ hc := &http.Client{Timeout: 1 * time.Minute}
+ resp, err := hc.Get(fmt.Sprintf(url, *version))
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer resp.Body.Close()
+ if resp.StatusCode != http.StatusOK {
+ log.Fatalf("HTTP status not OK: %s", resp.Status)
+ }
+
+ zr, err := gzip.NewReader(resp.Body)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer zr.Close()
+
+ var certs []*x509.Certificate
+ pool := x509.NewCertPool()
+
+ tr := tar.NewReader(zr)
+ for {
+ hdr, err := tr.Next()
+ if err == io.EOF {
+ break
+ }
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ rootsDirectory := fmt.Sprintf("security_certificates-%s/certificates/roots/", *version)
+ if dir, file := path.Split(hdr.Name); hdr.Typeflag != tar.TypeReg ||
+ dir != rootsDirectory || strings.HasPrefix(file, ".") {
+ continue
+ }
+
+ der, err := ioutil.ReadAll(tr)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ c, err := x509.ParseCertificate(der)
+ if err != nil {
+ log.Printf("Failed to parse certificate %q: %v", hdr.Name, err)
+ continue
+ }
+
+ certs = append(certs, c)
+ pool.AddCert(c)
+ }
+
+ // Quick smoke test to check the pool is well formed, and that we didn't end
+ // up trusting roots in the removed folder.
+ for _, c := range certs {
+ if c.Subject.CommonName == "Symantec Class 2 Public Primary Certification Authority - G4" {
+ log.Fatal("The pool includes a removed root!")
+ }
+ }
+ conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
+ RootCAs: pool,
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+ conn.Close()
+
+ certName := func(c *x509.Certificate) string {
+ if c.Subject.CommonName != "" {
+ return c.Subject.CommonName
+ }
+ if len(c.Subject.OrganizationalUnit) > 0 {
+ return c.Subject.OrganizationalUnit[0]
+ }
+ return c.Subject.Organization[0]
+ }
+ sort.Slice(certs, func(i, j int) bool {
+ if strings.ToLower(certName(certs[i])) != strings.ToLower(certName(certs[j])) {
+ return strings.ToLower(certName(certs[i])) < strings.ToLower(certName(certs[j]))
+ }
+ return certs[i].NotBefore.Before(certs[j].NotBefore)
+ })
+
+ out := new(bytes.Buffer)
+ fmt.Fprintf(out, header, *version)
+ fmt.Fprintf(out, "const systemRootsPEM = `\n")
+
+ for _, c := range certs {
+ fmt.Fprintf(out, "# %q\n", certName(c))
+ h := sha256.Sum256(c.Raw)
+ fmt.Fprintf(out, "# % X\n", h[:len(h)/2])
+ fmt.Fprintf(out, "# % X\n", h[len(h)/2:])
+ b := &pem.Block{
+ Type: "CERTIFICATE",
+ Bytes: c.Raw,
+ }
+ if err := pem.Encode(out, b); err != nil {
+ log.Fatal(err)
+ }
+ }
+
+ fmt.Fprintf(out, "`")
+
+ source, err := format.Source(out.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := ioutil.WriteFile(*output, source, 0644); err != nil {
+ log.Fatal(err)
+ }
+}
+
+const header = `// Code generated by root_darwin_ios_gen.go -version %s; DO NOT EDIT.
+// Update the version in root.go and regenerate with "go generate".
+
+// +build darwin,arm64 darwin,amd64,ios
+// +build !x509omitbundledroots
+
+package x509
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+// loadSystemRootsWithCgo is not available on iOS.
+var loadSystemRootsWithCgo func() (*CertPool, error)
+
+func loadSystemRoots() (*CertPool, error) {
+ p := NewCertPool()
+ p.AppendCertsFromPEM([]byte(systemRootsPEM))
+ return p, nil
+}
+`
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
index bd14d34b90..2c773b9120 100644
--- a/src/crypto/x509/root_darwin_test.go
+++ b/src/crypto/x509/root_darwin_test.go
@@ -5,120 +5,60 @@
package x509
import (
- "crypto/rsa"
"os"
"os/exec"
- "path/filepath"
- "runtime"
"testing"
"time"
)
func TestSystemRoots(t *testing.T) {
- switch runtime.GOARCH {
- case "arm64":
- t.Skipf("skipping on %s/%s, no system root", runtime.GOOS, runtime.GOARCH)
- }
-
t0 := time.Now()
- sysRoots := systemRootsPool() // actual system roots
+ sysRoots, err := loadSystemRoots() // actual system roots
sysRootsDuration := time.Since(t0)
- t1 := time.Now()
- execRoots, err := execSecurityRoots() // non-cgo roots
- execSysRootsDuration := time.Since(t1)
-
if err != nil {
t.Fatalf("failed to read system roots: %v", err)
}
- t.Logf(" cgo sys roots: %v", sysRootsDuration)
- t.Logf("non-cgo sys roots: %v", execSysRootsDuration)
+ t.Logf("loadSystemRoots: %v", sysRootsDuration)
- // On Mavericks, there are 212 bundled certs, at least there was at
- // one point in time on one machine. (Maybe it was a corp laptop
- // with extra certs?) Other OS X users report 135, 142, 145...
- // Let's try requiring at least 100, since this is just a sanity
- // check.
+ // There are 174 system roots on Catalina, and 163 on iOS right now, require
+ // at least 100 to make sure this is not completely broken.
if want, have := 100, len(sysRoots.certs); have < want {
t.Errorf("want at least %d system roots, have %d", want, have)
}
- // Fetch any intermediate certificate that verify-cert might be aware of.
- out, err := exec.Command("/usr/bin/security", "find-certificate", "-a", "-p",
- "/Library/Keychains/System.keychain",
- filepath.Join(os.Getenv("HOME"), "/Library/Keychains/login.keychain"),
- filepath.Join(os.Getenv("HOME"), "/Library/Keychains/login.keychain-db")).Output()
+ if loadSystemRootsWithCgo == nil {
+ t.Skip("cgo not available, can't compare pool")
+ }
+
+ t1 := time.Now()
+ cgoRoots, err := loadSystemRootsWithCgo() // cgo roots
+ cgoSysRootsDuration := time.Since(t1)
+
if err != nil {
- t.Fatal(err)
+ t.Fatalf("failed to read cgo roots: %v", err)
}
- allCerts := NewCertPool()
- allCerts.AppendCertsFromPEM(out)
+
+ t.Logf("loadSystemRootsWithCgo: %v", cgoSysRootsDuration)
// Check that the two cert pools are the same.
sysPool := make(map[string]*Certificate, len(sysRoots.certs))
for _, c := range sysRoots.certs {
sysPool[string(c.Raw)] = c
}
- for _, c := range execRoots.certs {
+ for _, c := range cgoRoots.certs {
if _, ok := sysPool[string(c.Raw)]; ok {
delete(sysPool, string(c.Raw))
} else {
- // verify-cert lets in certificates that are not trusted roots, but
- // are signed by trusted roots. This is not great, but unavoidable
- // until we parse real policies without cgo, so confirm that's the
- // case and skip them.
- if _, err := c.Verify(VerifyOptions{
- Roots: sysRoots,
- Intermediates: allCerts,
- KeyUsages: []ExtKeyUsage{ExtKeyUsageAny},
- CurrentTime: c.NotBefore, // verify-cert does not check expiration
- }); err != nil {
- t.Errorf("certificate only present in non-cgo pool: %v (verify error: %v)", c.Subject, err)
- } else {
- t.Logf("signed certificate only present in non-cgo pool (acceptable): %v", c.Subject)
- }
+ t.Errorf("certificate only present in cgo pool: %v", c.Subject)
}
}
for _, c := range sysPool {
- // The nocgo codepath uses verify-cert with the ssl policy, which also
- // happens to check EKUs, so some certificates will appear only in the
- // cgo pool. We can't easily make them consistent because the EKU check
- // is only applied to the certificates passed to verify-cert.
- var ekuOk bool
- for _, eku := range c.ExtKeyUsage {
- if eku == ExtKeyUsageServerAuth || eku == ExtKeyUsageNetscapeServerGatedCrypto ||
- eku == ExtKeyUsageMicrosoftServerGatedCrypto || eku == ExtKeyUsageAny {
- ekuOk = true
- }
- }
- if len(c.ExtKeyUsage) == 0 && len(c.UnknownExtKeyUsage) == 0 {
- ekuOk = true
- }
- if !ekuOk {
- t.Logf("off-EKU certificate only present in cgo pool (acceptable): %v", c.Subject)
- continue
- }
-
- // Same for expired certificates. We don't chain to them anyway.
- now := time.Now()
- if now.Before(c.NotBefore) || now.After(c.NotAfter) {
- t.Logf("expired certificate only present in cgo pool (acceptable): %v", c.Subject)
- continue
- }
-
- // On 10.11 there are five unexplained roots that only show up from the
- // C API. They have in common the fact that they are old, 1024-bit
- // certificates. It's arguably better to ignore them anyway.
- if key, ok := c.PublicKey.(*rsa.PublicKey); ok && key.N.BitLen() == 1024 {
- t.Logf("1024-bit certificate only present in cgo pool (acceptable): %v", c.Subject)
- continue
- }
-
- t.Errorf("certificate only present in cgo pool: %v", c.Subject)
+ t.Errorf("certificate only present in real pool: %v", c.Subject)
}
- if t.Failed() && debugDarwinRoots {
+ if t.Failed() {
cmd := exec.Command("security", "dump-trust-settings")
cmd.Stdout, cmd.Stderr = os.Stderr, os.Stderr
cmd.Run()
diff --git a/src/crypto/x509/root_nocgo_darwin.go b/src/crypto/x509/root_nocgo_darwin.go
deleted file mode 100644
index 2ac4666aff..0000000000
--- a/src/crypto/x509/root_nocgo_darwin.go
+++ /dev/null
@@ -1,11 +0,0 @@
-// Copyright 2013 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 !cgo
-
-package x509
-
-func loadSystemRoots() (*CertPool, error) {
- return execSecurityRoots()
-}
diff --git a/src/crypto/x509/root_omit.go b/src/crypto/x509/root_omit.go
index f466e24dce..175d71643b 100644
--- a/src/crypto/x509/root_omit.go
+++ b/src/crypto/x509/root_omit.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,arm64,x509omitbundledroots
+// +build darwin,arm64 darwin,amd64,ios
+// +build x509omitbundledroots
// This file provides the loadSystemRoots func when the
// "x509omitbundledroots" build tag has disabled bundling a copy,
@@ -19,3 +20,10 @@ import "errors"
func loadSystemRoots() (*CertPool, error) {
return nil, errors.New("x509: system root bundling disabled")
}
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+// loadSystemRootsWithCgo is not available on iOS.
+var loadSystemRootsWithCgo func() (*CertPool, error)
diff --git a/src/crypto/x509/root_omit_test.go b/src/crypto/x509/root_omit_test.go
index 2a9fb3f0c3..5ab6c931de 100644
--- a/src/crypto/x509/root_omit_test.go
+++ b/src/crypto/x509/root_omit_test.go
@@ -2,7 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build darwin,arm64,x509omitbundledroots
+// +build darwin,arm64 darwin,amd64,ios
+// +build x509omitbundledroots
package x509
diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go
index 39556ae60d..5a8015429c 100644
--- a/src/crypto/x509/root_unix_test.go
+++ b/src/crypto/x509/root_unix_test.go
@@ -204,7 +204,8 @@ func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
}
func TestReadUniqueDirectoryEntries(t *testing.T) {
- temp := func(base string) string { return filepath.Join(t.TempDir(), base) }
+ tmp := t.TempDir()
+ temp := func(base string) string { return filepath.Join(tmp, base) }
if f, err := os.Create(temp("file")); err != nil {
t.Fatal(err)
} else {
@@ -216,7 +217,7 @@ func TestReadUniqueDirectoryEntries(t *testing.T) {
if err := os.Symlink("../target-out", temp("link-out")); err != nil {
t.Fatal(err)
}
- got, err := readUniqueDirectoryEntries(t.TempDir())
+ got, err := readUniqueDirectoryEntries(tmp)
if err != nil {
t.Fatal(err)
}
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
index e01f55733c..d47f8382ae 100644
--- a/src/crypto/x509/verify.go
+++ b/src/crypto/x509/verify.go
@@ -19,7 +19,7 @@ import (
)
// ignoreCN disables interpreting Common Name as a hostname. See issue 24151.
-var ignoreCN = strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=1")
+var ignoreCN = !strings.Contains(os.Getenv("GODEBUG"), "x509ignoreCN=0")
type InvalidReason int
@@ -48,9 +48,9 @@ const (
// contains name constraints, and the Common Name can be interpreted as
// a hostname.
//
- // You can avoid this error by setting the experimental GODEBUG environment
- // variable to "x509ignoreCN=1", disabling Common Name matching entirely.
- // This behavior might become the default in the future.
+ // This error is only returned when legacy Common Name matching is enabled
+ // by setting the GODEBUG environment variable to "x509ignoreCN=1". This
+ // setting might be removed in the future.
NameConstraintsWithoutSANs
// UnconstrainedName results when a CA certificate contains permitted
// name constraints, but leaf certificate contains a name of an
@@ -109,10 +109,16 @@ type HostnameError struct {
func (h HostnameError) Error() string {
c := h.Certificate
- if !c.hasSANExtension() && !validHostname(c.Subject.CommonName) &&
- matchHostnames(toLowerCaseASCII(c.Subject.CommonName), toLowerCaseASCII(h.Host)) {
- // This would have validated, if it weren't for the validHostname check on Common Name.
- return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+ if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
+ if !ignoreCN && !validHostnamePattern(c.Subject.CommonName) {
+ // This would have validated, if it weren't for the validHostname check on Common Name.
+ return "x509: Common Name is not a valid hostname: " + c.Subject.CommonName
+ }
+ if ignoreCN && validHostnamePattern(c.Subject.CommonName) {
+ // This would have validated if x509ignoreCN=0 were set.
+ return "x509: certificate relies on legacy Common Name field, " +
+ "use SANs or temporarily enable Common Name matching with GODEBUG=x509ignoreCN=0"
+ }
}
var valid string
@@ -750,6 +756,12 @@ func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *V
// the name being validated. Note that DirectoryName constraints are not
// supported.
//
+// Name constraint validation follows the rules from RFC 5280, with the
+// addition that DNS name constraints may use the leading period format
+// defined for emails and URIs. When a constraint has a leading period
+// it indicates that at least one additional label must be prepended to
+// the constrained name to be considered valid.
+//
// Extended Key Usage values are enforced down a chain, so an intermediate or
// root that enumerates EKUs prevents a leaf from asserting an EKU not in that
// list.
@@ -908,12 +920,16 @@ func (c *Certificate) buildChains(cache map[*Certificate][][]*Certificate, curre
return
}
+func validHostnamePattern(host string) bool { return validHostname(host, true) }
+func validHostnameInput(host string) bool { return validHostname(host, false) }
+
// validHostname reports whether host is a valid hostname that can be matched or
// matched against according to RFC 6125 2.2, with some leniency to accommodate
// legacy values.
-func validHostname(host string) bool {
- host = strings.TrimSuffix(host, ".")
-
+func validHostname(host string, isPattern bool) bool {
+ if !isPattern {
+ host = strings.TrimSuffix(host, ".")
+ }
if len(host) == 0 {
return false
}
@@ -923,7 +939,7 @@ func validHostname(host string) bool {
// Empty label.
return false
}
- if i == 0 && part == "*" {
+ if isPattern && i == 0 && part == "*" {
// Only allow full left-most wildcards, as those are the only ones
// we match, and matching literal '*' characters is probably never
// the expected behavior.
@@ -942,8 +958,8 @@ func validHostname(host string) bool {
if c == '-' && j != 0 {
continue
}
- if c == '_' || c == ':' {
- // Not valid characters in hostnames, but commonly
+ if c == '_' {
+ // Not a valid character in hostnames, but commonly
// found in deployments outside the WebPKI.
continue
}
@@ -956,19 +972,26 @@ func validHostname(host string) bool {
// commonNameAsHostname reports whether the Common Name field should be
// considered the hostname that the certificate is valid for. This is a legacy
-// behavior, disabled if the Subject Alt Name extension is present.
+// behavior, disabled by default or if the Subject Alt Name extension is present.
//
// It applies the strict validHostname check to the Common Name field, so that
// certificates without SANs can still be validated against CAs with name
// constraints if there is no risk the CN would be matched as a hostname.
// See NameConstraintsWithoutSANs and issue 24151.
func (c *Certificate) commonNameAsHostname() bool {
- return !ignoreCN && !c.hasSANExtension() && validHostname(c.Subject.CommonName)
+ return !ignoreCN && !c.hasSANExtension() && validHostnamePattern(c.Subject.CommonName)
+}
+
+func matchExactly(hostA, hostB string) bool {
+ if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
+ return false
+ }
+ return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
}
func matchHostnames(pattern, host string) bool {
- host = strings.TrimSuffix(host, ".")
- pattern = strings.TrimSuffix(pattern, ".")
+ pattern = toLowerCaseASCII(pattern)
+ host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
if len(pattern) == 0 || len(host) == 0 {
return false
@@ -1030,13 +1053,13 @@ func toLowerCaseASCII(in string) string {
//
// IP addresses can be optionally enclosed in square brackets and are checked
// against the IPAddresses field. Other names are checked case insensitively
-// against the DNSNames field, with support for only one wildcard as the whole
-// left-most label.
+// against the DNSNames field. If the names are valid hostnames, the certificate
+// fields can have a wildcard as the left-most label.
//
-// If the Common Name field is a valid hostname, and the certificate doesn't
-// have any Subject Alternative Names, the name will also be checked against the
-// Common Name. This legacy behavior can be disabled by setting the GODEBUG
-// environment variable to "x509ignoreCN=1" and might be removed in the future.
+// The legacy Common Name field is ignored unless it's a valid hostname, the
+// certificate doesn't have any Subject Alternative Names, and the GODEBUG
+// environment variable is set to "x509ignoreCN=0". Support for Common Name is
+// deprecated will be entirely removed in the future.
func (c *Certificate) VerifyHostname(h string) error {
// IP addresses may be written in [ ].
candidateIP := h
@@ -1054,15 +1077,26 @@ func (c *Certificate) VerifyHostname(h string) error {
return HostnameError{c, candidateIP}
}
- lowered := toLowerCaseASCII(h)
-
+ names := c.DNSNames
if c.commonNameAsHostname() {
- if matchHostnames(toLowerCaseASCII(c.Subject.CommonName), lowered) {
- return nil
- }
- } else {
- for _, match := range c.DNSNames {
- if matchHostnames(toLowerCaseASCII(match), lowered) {
+ names = []string{c.Subject.CommonName}
+ }
+
+ candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
+ validCandidateName := validHostnameInput(candidateName)
+
+ for _, match := range names {
+ // Ideally, we'd only match valid hostnames according to RFC 6125 like
+ // browsers (more or less) do, but in practice Go is used in a wider
+ // array of contexts and can't even assume DNS resolution. Instead,
+ // always allow perfect matches, and only apply wildcard and trailing
+ // dot processing to valid hostnames.
+ if validCandidateName && validHostnamePattern(match) {
+ if matchHostnames(match, candidateName) {
+ return nil
+ }
+ } else {
+ if matchExactly(match, candidateName) {
return nil
}
}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
index 86fe76a57d..650b2d2fc6 100644
--- a/src/crypto/x509/verify_test.go
+++ b/src/crypto/x509/verify_test.go
@@ -374,7 +374,7 @@ var verifyTests = []verifyTest{
systemSkip: true,
ignoreCN: true,
- errorCallback: expectHostnameError("Common Name is not a valid hostname"),
+ errorCallback: expectHostnameError("not valid for any names"),
},
{
leaf: validCNWithoutSAN,
@@ -384,7 +384,7 @@ var verifyTests = []verifyTest{
systemSkip: true,
ignoreCN: true,
- errorCallback: expectHostnameError("not valid for any names"),
+ errorCallback: expectHostnameError("certificate relies on legacy Common Name field"),
},
{
// A certificate with an AKID should still chain to a parent without SKID.
@@ -1987,26 +1987,31 @@ CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
func TestValidHostname(t *testing.T) {
tests := []struct {
- host string
- want bool
+ host string
+ validInput, validPattern bool
}{
- {"example.com", true},
- {"eXample123-.com", true},
- {"-eXample123-.com", false},
- {"", false},
- {".", false},
- {"example..com", false},
- {".example.com", false},
- {"*.example.com", true},
- {"*foo.example.com", false},
- {"foo.*.example.com", false},
- {"exa_mple.com", true},
- {"foo,bar", false},
- {"project-dev:us-central1:main", true},
+ {host: "example.com", validInput: true, validPattern: true},
+ {host: "eXample123-.com", validInput: true, validPattern: true},
+ {host: "-eXample123-.com"},
+ {host: ""},
+ {host: "."},
+ {host: "example..com"},
+ {host: ".example.com"},
+ {host: "example.com.", validInput: true},
+ {host: "*.example.com."},
+ {host: "*.example.com", validPattern: true},
+ {host: "*foo.example.com"},
+ {host: "foo.*.example.com"},
+ {host: "exa_mple.com", validInput: true, validPattern: true},
+ {host: "foo,bar"},
+ {host: "project-dev:us-central1:main"},
}
for _, tt := range tests {
- if got := validHostname(tt.host); got != tt.want {
- t.Errorf("validHostname(%q) = %v, want %v", tt.host, got, tt.want)
+ if got := validHostnamePattern(tt.host); got != tt.validPattern {
+ t.Errorf("validHostnamePattern(%q) = %v, want %v", tt.host, got, tt.validPattern)
+ }
+ if got := validHostnameInput(tt.host); got != tt.validInput {
+ t.Errorf("validHostnameInput(%q) = %v, want %v", tt.host, got, tt.validInput)
}
}
}
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
index ecf44071cf..9cc3acdb3f 100644
--- a/src/crypto/x509/x509.go
+++ b/src/crypto/x509/x509.go
@@ -3,10 +3,6 @@
// license that can be found in the LICENSE file.
// Package x509 parses X.509-encoded keys and certificates.
-//
-// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR
-// can be used to override the system default locations for the SSL certificate
-// file and SSL certificate files directory, respectively.
package x509
import (
@@ -2100,7 +2096,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return nil, errors.New("x509: no SerialNumber given")
}
- if template.BasicConstraintsValid && !template.IsCA && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
+ if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
}
@@ -2129,16 +2125,13 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
authorityKeyId = parent.SubjectKeyId
}
- encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
- pki := publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey}
subjectKeyId := template.SubjectKeyId
if len(subjectKeyId) == 0 && template.IsCA {
- // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2
- b, err := asn1.Marshal(pki)
- if err != nil {
- return nil, err
- }
- h := sha1.Sum(b)
+ // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2:
+ // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ // value of the BIT STRING subjectPublicKey (excluding the tag,
+ // length, and number of unused bits).
+ h := sha1.Sum(publicKeyBytes)
subjectKeyId = h[:]
}
@@ -2147,6 +2140,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
return
}
+ encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
c := tbsCertificate{
Version: 2,
SerialNumber: template.SerialNumber,
@@ -2154,7 +2148,7 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv
Issuer: asn1.RawValue{FullBytes: asn1Issuer},
Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
Subject: asn1.RawValue{FullBytes: asn1Subject},
- PublicKey: pki,
+ PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
Extensions: extensions,
}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
index 05bade5a8f..0141021504 100644
--- a/src/crypto/x509/x509_test.go
+++ b/src/crypto/x509/x509_test.go
@@ -357,25 +357,40 @@ var matchHostnamesTests = []matchHostnamesTest{
{"*.example.com", "www.example.com", true},
{"*.example.com", "www.example.com.", true},
{"*.example.com", "xyz.www.example.com", false},
+ {"*.example.com", "https://www.example.com", false}, // Issue 27591
+ {"*.example..com", "www.example..com", false},
+ {"www.example..com", "www.example..com", true},
{"*.*.example.com", "xyz.www.example.com", false},
{"*.www.*.com", "xyz.www.example.com", false},
{"*bar.example.com", "foobar.example.com", false},
{"f*.example.com", "foobar.example.com", false},
+ {"www.example.com", "*.example.com", false},
{"", ".", false},
{".", "", false},
{".", ".", false},
{"example.com", "example.com.", true},
- {"example.com.", "example.com", true},
- {"example.com.", "example.com.", true},
- {"*.com.", "example.com.", true},
- {"*.com.", "example.com", true},
+ {"example.com.", "example.com", false},
+ {"example.com.", "example.com.", true}, // perfect matches allow trailing dots in patterns
+ {"*.com.", "example.com.", false},
+ {"*.com.", "example.com", false},
{"*.com", "example.com", true},
{"*.com", "example.com.", true},
+ {"foo:bar", "foo:bar", true},
+ {"*.foo:bar", "xxx.foo:bar", false},
+ {"*.2.3.4", "1.2.3.4", false},
+ {"*.2.3.4", "[1.2.3.4]", false},
+ {"*:4860:4860::8888", "2001:4860:4860::8888", false},
+ {"*:4860:4860::8888", "[2001:4860:4860::8888]", false},
+ {"2001:4860:4860::8888", "2001:4860:4860::8888", false},
+ {"2001:4860:4860::8888", "[2001:4860:4860::8888]", false},
+ {"[2001:4860:4860::8888]", "2001:4860:4860::8888", false},
+ {"[2001:4860:4860::8888]", "[2001:4860:4860::8888]", false},
}
func TestMatchHostnames(t *testing.T) {
for i, test := range matchHostnamesTests {
- r := matchHostnames(test.pattern, test.host)
+ c := &Certificate{DNSNames: []string{test.pattern}}
+ r := c.VerifyHostname(test.host) == nil
if r != test.ok {
t.Errorf("#%d mismatch got: %t want: %t when matching '%s' against '%s'", i, r, test.ok, test.host, test.pattern)
}
@@ -426,7 +441,7 @@ func TestMatchIP(t *testing.T) {
}
func TestCertificateParse(t *testing.T) {
- s, _ := hex.DecodeString(certBytes)
+ s, _ := base64.StdEncoding.DecodeString(certBytes)
certs, err := ParseCertificates(s)
if err != nil {
t.Error(err)
@@ -445,7 +460,7 @@ func TestCertificateParse(t *testing.T) {
t.Error(err)
}
- const expectedExtensions = 4
+ const expectedExtensions = 10
if n := len(certs[0].Extensions); n != expectedExtensions {
t.Errorf("want %d extensions, got %d", expectedExtensions, n)
}
@@ -489,48 +504,50 @@ func TestMismatchedSignatureAlgorithm(t *testing.T) {
}
}
-var certBytes = "308203223082028ba00302010202106edf0d9499fd4533dd1297fc42a93be1300d06092a864886" +
- "f70d0101050500304c310b3009060355040613025a4131253023060355040a131c546861777465" +
- "20436f6e73756c74696e67202850747929204c74642e311630140603550403130d546861777465" +
- "20534743204341301e170d3039303332353136343932395a170d3130303332353136343932395a" +
- "3069310b3009060355040613025553311330110603550408130a43616c69666f726e6961311630" +
- "140603550407130d4d6f756e7461696e205669657731133011060355040a130a476f6f676c6520" +
- "496e63311830160603550403130f6d61696c2e676f6f676c652e636f6d30819f300d06092a8648" +
- "86f70d010101050003818d0030818902818100c5d6f892fccaf5614b064149e80a2c9581a218ef" +
- "41ec35bd7a58125ae76f9ea54ddc893abbeb029f6b73616bf0ffd868791fba7af9c4aebf3706ba" +
- "3eeaeed27435b4ddcfb157c05f351d66aa87fee0de072d66d773affbd36ab78bef090e0cc861a9" +
- "03ac90dd98b51c9c41566c017f0beec3bff391051ffba0f5cc6850ad2a590203010001a381e730" +
- "81e430280603551d250421301f06082b0601050507030106082b06010505070302060960864801" +
- "86f842040130360603551d1f042f302d302ba029a0278625687474703a2f2f63726c2e74686177" +
- "74652e636f6d2f54686177746553474343412e63726c307206082b060105050701010466306430" +
- "2206082b060105050730018616687474703a2f2f6f6373702e7468617774652e636f6d303e0608" +
- "2b060105050730028632687474703a2f2f7777772e7468617774652e636f6d2f7265706f736974" +
- "6f72792f5468617774655f5347435f43412e637274300c0603551d130101ff04023000300d0609" +
- "2a864886f70d01010505000381810062f1f3050ebc105e497c7aedf87e24d2f4a986bb3b837bd1" +
- "9b91ebcad98b065992f6bd2b49b7d6d3cb2e427a99d606c7b1d46352527fac39e6a8b6726de5bf" +
- "70212a52cba07634a5e332011bd1868e78eb5e3c93cf03072276786f207494feaa0ed9d53b2110" +
- "a76571f90209cdae884385c882587030ee15f33d761e2e45a6bc308203233082028ca003020102" +
- "020430000002300d06092a864886f70d0101050500305f310b3009060355040613025553311730" +
- "15060355040a130e566572695369676e2c20496e632e31373035060355040b132e436c61737320" +
- "33205075626c6963205072696d6172792043657274696669636174696f6e20417574686f726974" +
- "79301e170d3034303531333030303030305a170d3134303531323233353935395a304c310b3009" +
- "060355040613025a4131253023060355040a131c54686177746520436f6e73756c74696e672028" +
- "50747929204c74642e311630140603550403130d5468617774652053474320434130819f300d06" +
- "092a864886f70d010101050003818d0030818902818100d4d367d08d157faecd31fe7d1d91a13f" +
- "0b713cacccc864fb63fc324b0794bd6f80ba2fe10493c033fc093323e90b742b71c403c6d2cde2" +
- "2ff50963cdff48a500bfe0e7f388b72d32de9836e60aad007bc4644a3b847503f270927d0e62f5" +
- "21ab693684317590f8bfc76c881b06957cc9e5a8de75a12c7a68dfd5ca1c875860190203010001" +
- "a381fe3081fb30120603551d130101ff040830060101ff020100300b0603551d0f040403020106" +
- "301106096086480186f842010104040302010630280603551d110421301fa41d301b3119301706" +
- "035504031310507269766174654c6162656c332d313530310603551d1f042a30283026a024a022" +
- "8620687474703a2f2f63726c2e766572697369676e2e636f6d2f706361332e63726c303206082b" +
- "0601050507010104263024302206082b060105050730018616687474703a2f2f6f6373702e7468" +
- "617774652e636f6d30340603551d25042d302b06082b0601050507030106082b06010505070302" +
- "06096086480186f8420401060a6086480186f845010801300d06092a864886f70d010105050003" +
- "81810055ac63eadea1ddd2905f9f0bce76be13518f93d9052bc81b774bad6950a1eededcfddb07" +
- "e9e83994dcab72792f06bfab8170c4a8edea5334edef1e53d906c7562bd15cf4d18a8eb42bb137" +
- "9048084225c53e8acb7feb6f04d16dc574a2f7a27c7b603c77cd0ece48027f012fb69b37e02a2a" +
- "36dcd585d6ace53f546f961e05af"
+var certBytes = "MIIE0jCCA7qgAwIBAgIQWcvS+TTB3GwCAAAAAGEAWzANBgkqhkiG9w0BAQsFADBCMQswCQYD" +
+ "VQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMRMwEQYDVQQDEwpHVFMg" +
+ "Q0EgMU8xMB4XDTIwMDQwMTEyNTg1NloXDTIwMDYyNDEyNTg1NlowaTELMAkGA1UEBhMCVVMx" +
+ "EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxEzARBgNVBAoT" +
+ "Ckdvb2dsZSBMTEMxGDAWBgNVBAMTD21haWwuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG" +
+ "SM49AwEHA0IABO+dYiPnkFl+cZVf6mrWeNp0RhQcJSBGH+sEJxjvc+cYlW3QJCnm57qlpFdd" +
+ "pz3MPyVejvXQdM6iI1mEWP4C2OujggJmMIICYjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww" +
+ "CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUI6pZhnQ/lQgmPDwSKR2A54G7" +
+ "AS4wHwYDVR0jBBgwFoAUmNH4bhDrz5vsYJ8YkBug630J/SswZAYIKwYBBQUHAQEEWDBWMCcG" +
+ "CCsGAQUFBzABhhtodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHMxbzEwKwYIKwYBBQUHMAKGH2h0" +
+ "dHA6Ly9wa2kuZ29vZy9nc3IyL0dUUzFPMS5jcnQwLAYDVR0RBCUwI4IPbWFpbC5nb29nbGUu" +
+ "Y29tghBpbmJveC5nb29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQICMAwGCisGAQQB1nkC" +
+ "BQMwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5wa2kuZ29vZy9HVFMxTzEuY3JsMIIB" +
+ "AwYKKwYBBAHWeQIEAgSB9ASB8QDvAHYAsh4FzIuizYogTodm+Su5iiUgZ2va+nDnsklTLe+L" +
+ "kF4AAAFxNgmxKgAABAMARzBFAiEA12/OHdTGXQ3qHHC3NvYCyB8aEz/+ZFOLCAI7lhqj28sC" +
+ "IG2/7Yz2zK6S6ai+dH7cTMZmoFGo39gtaTqtZAqEQX7nAHUAXqdz+d9WwOe1Nkh90EngMnqR" +
+ "mgyEoRIShBh1loFxRVgAAAFxNgmxTAAABAMARjBEAiA7PNq+MFfv6O9mBkxFViS2TfU66yRB" +
+ "/njcebWglLQjZQIgOyRKhxlEizncFRml7yn4Bg48ktXKGjo+uiw6zXEINb0wDQYJKoZIhvcN" +
+ "AQELBQADggEBADM2Rh306Q10PScsolYMxH1B/K4Nb2WICvpY0yDPJFdnGjqCYym196TjiEvs" +
+ "R6etfeHdyzlZj6nh82B4TVyHjiWM02dQgPalOuWQcuSy0OvLh7F1E7CeHzKlczdFPBTOTdM1" +
+ "RDTxlvw1bAqc0zueM8QIAyEy3opd7FxAcGQd5WRIJhzLBL+dbbMOW/LTeW7cm/Xzq8cgCybN" +
+ "BSZAvhjseJ1L29OlCTZL97IfnX0IlFQzWuvvHy7V2B0E3DHlzM0kjwkkCKDUUp/wajv2NZKC" +
+ "TkhEyERacZRKc9U0ADxwsAzHrdz5+5zfD2usEV/MQ5V6d8swLXs+ko0X6swrd4YCiB8wggRK" +
+ "MIIDMqADAgECAg0B47SaoY2KqYElaVC4MA0GCSqGSIb3DQEBCwUAMEwxIDAeBgNVBAsTF0ds" +
+ "b2JhbFNpZ24gUm9vdCBDQSAtIFIyMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpH" +
+ "bG9iYWxTaWduMB4XDTE3MDYxNTAwMDA0MloXDTIxMTIxNTAwMDA0MlowQjELMAkGA1UEBhMC" +
+ "VVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczETMBEGA1UEAxMKR1RTIENBIDFP" +
+ "MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAYz0XUi83TnORA73603WkhG8nP" +
+ "PI5MdbkPMRmEPZ48Ke9QDRCTbwWAgJ8qoL0SSwLhPZ9YFiT+MJ8LdHdVkx1L903hkoIQ9lGs" +
+ "DMOyIpQPNGuYEEnnC52DOd0gxhwt79EYYWXnI4MgqCMS/9Ikf9Qv50RqW03XUGawr55CYwX7" +
+ "4BzEY2Gvn2oz/2KXvUjZ03wUZ9x13C5p6PhteGnQtxAFuPExwjsk/RozdPgj4OxrGYoWxuPN" +
+ "pM0L27OkWWA4iDutHbnGjKdTG/y82aSrvN08YdeTFZjugb2P4mRHIEAGTtesl+i5wFkSoUkl" +
+ "I+TtcDQspbRjfPmjPYPRzW0krAcCAwEAAaOCATMwggEvMA4GA1UdDwEB/wQEAwIBhjAdBgNV" +
+ "HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E" +
+ "FgQUmNH4bhDrz5vsYJ8YkBug630J/SswHwYDVR0jBBgwFoAUm+IHV2ccHsBqBt5ZtJot39wZ" +
+ "hi4wNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5wa2kuZ29vZy9n" +
+ "c3IyMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMi9nc3IyLmNy" +
+ "bDA/BgNVHSAEODA2MDQGBmeBDAECAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3BraS5nb29n" +
+ "L3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAagD42efvzLqlGN31eVBY1rsdOCJn+" +
+ "vdE0aSZSZgc9CrpJy2L08RqO/BFPaJZMdCvTZ96yo6oFjYRNTCBlD6WW2g0W+Gw7228EI4hr" +
+ "OmzBYL1on3GO7i1YNAfw1VTphln9e14NIZT1jMmo+NjyrcwPGvOap6kEJ/mjybD/AnhrYbrH" +
+ "NSvoVvpPwxwM7bY8tEvq7czhPOzcDYzWPpvKQliLzBYhF0C8otZm79rEFVvNiaqbCSbnMtIN" +
+ "bmcgAlsQsJAJnAwfnq3YO+qh/GzoEFwIUhlRKnG7rHq13RXtK8kIKiyKtKYhq2P/11JJUNCJ" +
+ "t63yr/tQri/hlQ3zRq2dnPXK"
func parseCIDR(s string) *net.IPNet {
_, net, err := net.ParseCIDR(s)
@@ -1657,11 +1674,15 @@ func TestMaxPathLenNotCA(t *testing.T) {
BasicConstraintsValid: true,
IsCA: false,
}
- cert := serialiseAndParse(t, template)
- if m := cert.MaxPathLen; m != -1 {
+ if m := serialiseAndParse(t, template).MaxPathLen; m != -1 {
t.Errorf("MaxPathLen should be -1 when IsCa is false, got %d", m)
}
+ template.MaxPathLen = -1
+ if m := serialiseAndParse(t, template).MaxPathLen; m != -1 {
+ t.Errorf("MaxPathLen should be -1 when IsCa is false and MaxPathLen set to -1, got %d", m)
+ }
+
template.MaxPathLen = 5
if _, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey); err == nil {
t.Error("specifying a MaxPathLen when IsCA is false should fail")
@@ -1674,8 +1695,7 @@ func TestMaxPathLenNotCA(t *testing.T) {
}
template.BasicConstraintsValid = false
- cert2 := serialiseAndParse(t, template)
- if m := cert2.MaxPathLen; m != 0 {
+ if m := serialiseAndParse(t, template).MaxPathLen; m != 0 {
t.Errorf("Bad MaxPathLen should be ignored if BasicConstraintsValid is false, got %d", m)
}
}
@@ -2047,11 +2067,11 @@ func TestEmptyNameConstraints(t *testing.T) {
}
func TestPKIXNameString(t *testing.T) {
- pem, err := hex.DecodeString(certBytes)
+ der, err := base64.StdEncoding.DecodeString(certBytes)
if err != nil {
t.Fatal(err)
}
- certs, err := ParseCertificates(pem)
+ certs, err := ParseCertificates(der)
if err != nil {
t.Fatal(err)
}
@@ -2072,7 +2092,7 @@ func TestPKIXNameString(t *testing.T) {
Country: []string{"GB"},
}, "SERIALNUMBER=RFC 2253,CN=Steve Kille,OU=RFCs,O=Isode Limited,POSTALCODE=TW9 1DT,STREET=The Square,L=Richmond,ST=Surrey,C=GB"},
{certs[0].Subject,
- "CN=mail.google.com,O=Google Inc,L=Mountain View,ST=California,C=US"},
+ "CN=mail.google.com,O=Google LLC,L=Mountain View,ST=California,C=US"},
{pkix.Name{
Organization: []string{"#Google, Inc. \n-> 'Alphabet\" "},
Country: []string{"US"},
diff --git a/src/database/sql/driver/driver.go b/src/database/sql/driver/driver.go
index 99fbd431be..5bbcf20db2 100644
--- a/src/database/sql/driver/driver.go
+++ b/src/database/sql/driver/driver.go
@@ -96,7 +96,7 @@ type Driver interface {
// If a Driver implements DriverContext, then sql.DB will call
// OpenConnector to obtain a Connector and then invoke
-// that Connector's Conn method to obtain each needed connection,
+// that Connector's Connect method to obtain each needed connection,
// instead of invoking the Driver's Open method for each connection.
// The two-step sequence allows drivers to parse the name just once
// and also provides access to per-Conn contexts.
diff --git a/src/database/sql/sql.go b/src/database/sql/sql.go
index 374dd98b00..b3d0653f5c 100644
--- a/src/database/sql/sql.go
+++ b/src/database/sql/sql.go
@@ -3013,10 +3013,11 @@ func (ci *ColumnType) Nullable() (nullable, ok bool) {
}
// DatabaseTypeName returns the database system name of the column type. If an empty
-// string is returned the driver type name is not supported.
+// string is returned, then the driver type name is not supported.
// Consult your driver documentation for a list of driver data types. Length specifiers
// are not included.
-// Common type include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL", "INT", "BIGINT".
+// Common type names include "VARCHAR", "TEXT", "NVARCHAR", "DECIMAL", "BOOL",
+// "INT", and "BIGINT".
func (ci *ColumnType) DatabaseTypeName() string {
return ci.databaseType
}
diff --git a/src/encoding/asn1/asn1.go b/src/encoding/asn1/asn1.go
index fd4dd68021..d809dde278 100644
--- a/src/encoding/asn1/asn1.go
+++ b/src/encoding/asn1/asn1.go
@@ -313,6 +313,12 @@ func parseBase128Int(bytes []byte, initOffset int) (ret, offset int, err error)
}
ret64 <<= 7
b := bytes[offset]
+ // integers should be minimally encoded, so the leading octet should
+ // never be 0x80
+ if shifted == 0 && b == 0x80 {
+ err = SyntaxError{"integer is not minimally encoded"}
+ return
+ }
ret64 |= int64(b & 0x7f)
offset++
if b&0x80 == 0 {
@@ -1031,6 +1037,12 @@ func setDefaultValue(v reflect.Value, params fieldParameters) (ok bool) {
// Because Unmarshal uses the reflect package, the structs
// being written to must use upper case field names.
//
+// After parsing b, any bytes that were leftover and not used to fill
+// val will be returned in rest. When parsing a SEQUENCE into a struct,
+// any trailing elements of the SEQUENCE that do not have matching
+// fields in val will not be included in rest, as these are considered
+// valid elements of the SEQUENCE and not trailing data.
+//
// An ASN.1 INTEGER can be written to an int, int32, int64,
// or *big.Int (from the math/big package).
// If the encoded value does not fit in the Go type,
diff --git a/src/encoding/asn1/asn1_test.go b/src/encoding/asn1/asn1_test.go
index d5649bff9f..8daae97faa 100644
--- a/src/encoding/asn1/asn1_test.go
+++ b/src/encoding/asn1/asn1_test.go
@@ -1129,3 +1129,15 @@ func TestBMPString(t *testing.T) {
}
}
}
+
+func TestNonMinimalEncodedOID(t *testing.T) {
+ h, err := hex.DecodeString("060a2a80864886f70d01010b")
+ if err != nil {
+ t.Fatalf("failed to decode from hex string: %s", err)
+ }
+ var oid ObjectIdentifier
+ _, err = Unmarshal(h, &oid)
+ if err == nil {
+ t.Fatalf("accepted non-minimally encoded oid")
+ }
+}
diff --git a/src/encoding/asn1/marshal.go b/src/encoding/asn1/marshal.go
index c9ae2ca33e..0d34d5aa1e 100644
--- a/src/encoding/asn1/marshal.go
+++ b/src/encoding/asn1/marshal.go
@@ -5,10 +5,12 @@
package asn1
import (
+ "bytes"
"errors"
"fmt"
"math/big"
"reflect"
+ "sort"
"time"
"unicode/utf8"
)
@@ -78,6 +80,48 @@ func (m multiEncoder) Encode(dst []byte) {
}
}
+type setEncoder []encoder
+
+func (s setEncoder) Len() int {
+ var size int
+ for _, e := range s {
+ size += e.Len()
+ }
+ return size
+}
+
+func (s setEncoder) Encode(dst []byte) {
+ // Per X690 Section 11.6: The encodings of the component values of a
+ // set-of value shall appear in ascending order, the encodings being
+ // compared as octet strings with the shorter components being padded
+ // at their trailing end with 0-octets.
+ //
+ // First we encode each element to its TLV encoding and then use
+ // octetSort to get the ordering expected by X690 DER rules before
+ // writing the sorted encodings out to dst.
+ l := make([][]byte, len(s))
+ for i, e := range s {
+ l[i] = make([]byte, e.Len())
+ e.Encode(l[i])
+ }
+
+ sort.Slice(l, func(i, j int) bool {
+ // Since we are using bytes.Compare to compare TLV encodings we
+ // don't need to right pad s[i] and s[j] to the same length as
+ // suggested in X690. If len(s[i]) < len(s[j]) the length octet of
+ // s[i], which is the first determining byte, will inherently be
+ // smaller than the length octet of s[j]. This lets us skip the
+ // padding step.
+ return bytes.Compare(l[i], l[j]) < 0
+ })
+
+ var off int
+ for _, b := range l {
+ copy(dst[off:], b)
+ off += len(b)
+ }
+}
+
type taggedEncoder struct {
// scratch contains temporary space for encoding the tag and length of
// an element in order to avoid extra allocations.
@@ -511,6 +555,9 @@ func makeBody(value reflect.Value, params fieldParameters) (e encoder, err error
}
}
+ if params.set {
+ return setEncoder(m), nil
+ }
return multiEncoder(m), nil
}
case reflect.String:
@@ -618,6 +665,15 @@ func makeField(v reflect.Value, params fieldParameters) (e encoder, err error) {
tag = TagSet
}
+ // makeField can be called for a slice that should be treated as a SET
+ // but doesn't have params.set set, for instance when using a slice
+ // with the SET type name suffix. In this case getUniversalType returns
+ // TagSet, but makeBody doesn't know about that so will treat the slice
+ // as a sequence. To work around this we set params.set.
+ if tag == TagSet && !params.set {
+ params.set = true
+ }
+
t := new(taggedEncoder)
t.body, err = makeBody(v, params)
diff --git a/src/encoding/asn1/marshal_test.go b/src/encoding/asn1/marshal_test.go
index a77826a7b0..529052285f 100644
--- a/src/encoding/asn1/marshal_test.go
+++ b/src/encoding/asn1/marshal_test.go
@@ -319,3 +319,60 @@ func BenchmarkMarshal(b *testing.B) {
}
}
}
+
+func TestSetEncoder(t *testing.T) {
+ testStruct := struct {
+ Strings []string `asn1:"set"`
+ }{
+ Strings: []string{"a", "aa", "b", "bb", "c", "cc"},
+ }
+
+ // Expected ordering of the SET should be:
+ // a, b, c, aa, bb, cc
+
+ output, err := Marshal(testStruct)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+
+ expectedOrder := []string{"a", "b", "c", "aa", "bb", "cc"}
+ var resultStruct struct {
+ Strings []string `asn1:"set"`
+ }
+ rest, err := Unmarshal(output, &resultStruct)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+ if len(rest) != 0 {
+ t.Error("Unmarshal returned extra garbage")
+ }
+ if !reflect.DeepEqual(expectedOrder, resultStruct.Strings) {
+ t.Errorf("Unexpected SET content. got: %s, want: %s", resultStruct.Strings, expectedOrder)
+ }
+}
+
+func TestSetEncoderSETSliceSuffix(t *testing.T) {
+ type testSetSET []string
+ testSet := testSetSET{"a", "aa", "b", "bb", "c", "cc"}
+
+ // Expected ordering of the SET should be:
+ // a, b, c, aa, bb, cc
+
+ output, err := Marshal(testSet)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+
+ expectedOrder := testSetSET{"a", "b", "c", "aa", "bb", "cc"}
+ var resultSet testSetSET
+ rest, err := Unmarshal(output, &resultSet)
+ if err != nil {
+ t.Errorf("%v", err)
+ }
+ if len(rest) != 0 {
+ t.Error("Unmarshal returned extra garbage")
+ }
+ if !reflect.DeepEqual(expectedOrder, resultSet) {
+ t.Errorf("Unexpected SET content. got: %s, want: %s", resultSet, expectedOrder)
+ }
+}
diff --git a/src/encoding/json/decode.go b/src/encoding/json/decode.go
index b43484692e..86d8a69db7 100644
--- a/src/encoding/json/decode.go
+++ b/src/encoding/json/decode.go
@@ -213,9 +213,6 @@ type decodeState struct {
savedError error
useNumber bool
disallowUnknownFields bool
- // safeUnquote is the number of current string literal bytes that don't
- // need to be unquoted. When negative, no bytes need unquoting.
- safeUnquote int
}
// readIndex returns the position of the last byte read.
@@ -317,27 +314,13 @@ func (d *decodeState) rescanLiteral() {
Switch:
switch data[i-1] {
case '"': // string
- // safeUnquote is initialized at -1, which means that all bytes
- // checked so far can be unquoted at a later time with no work
- // at all. When reaching the closing '"', if safeUnquote is
- // still -1, all bytes can be unquoted with no work. Otherwise,
- // only those bytes up until the first '\\' or non-ascii rune
- // can be safely unquoted.
- safeUnquote := -1
for ; i < len(data); i++ {
- if c := data[i]; c == '\\' {
- if safeUnquote < 0 { // first unsafe byte
- safeUnquote = int(i - d.off)
- }
+ switch data[i] {
+ case '\\':
i++ // escaped char
- } else if c == '"' {
- d.safeUnquote = safeUnquote
+ case '"':
i++ // tokenize the closing quote too
break Switch
- } else if c >= utf8.RuneSelf {
- if safeUnquote < 0 { // first unsafe byte
- safeUnquote = int(i - d.off)
- }
}
}
case '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '-': // number
@@ -691,7 +674,7 @@ func (d *decodeState) object(v reflect.Value) error {
start := d.readIndex()
d.rescanLiteral()
item := d.data[start:d.readIndex()]
- key, ok := d.unquoteBytes(item)
+ key, ok := unquoteBytes(item)
if !ok {
panic(phasePanicMsg)
}
@@ -892,7 +875,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
d.saveError(&UnmarshalTypeError{Value: val, Type: v.Type(), Offset: int64(d.readIndex())})
return nil
}
- s, ok := d.unquoteBytes(item)
+ s, ok := unquoteBytes(item)
if !ok {
if fromQuoted {
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
@@ -943,7 +926,7 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool
}
case '"': // string
- s, ok := d.unquoteBytes(item)
+ s, ok := unquoteBytes(item)
if !ok {
if fromQuoted {
return fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type())
@@ -1103,7 +1086,7 @@ func (d *decodeState) objectInterface() map[string]interface{} {
start := d.readIndex()
d.rescanLiteral()
item := d.data[start:d.readIndex()]
- key, ok := d.unquote(item)
+ key, ok := unquote(item)
if !ok {
panic(phasePanicMsg)
}
@@ -1152,7 +1135,7 @@ func (d *decodeState) literalInterface() interface{} {
return c == 't'
case '"': // string
- s, ok := d.unquote(item)
+ s, ok := unquote(item)
if !ok {
panic(phasePanicMsg)
}
@@ -1195,26 +1178,38 @@ func getu4(s []byte) rune {
// unquote converts a quoted JSON string literal s into an actual string t.
// The rules are different than for Go, so cannot use strconv.Unquote.
-// The first byte in s must be '"'.
-func (d *decodeState) unquote(s []byte) (t string, ok bool) {
- s, ok = d.unquoteBytes(s)
+func unquote(s []byte) (t string, ok bool) {
+ s, ok = unquoteBytes(s)
t = string(s)
return
}
-func (d *decodeState) unquoteBytes(s []byte) (t []byte, ok bool) {
- // We already know that s[0] == '"'. However, we don't know that the
- // closing quote exists in all cases, such as when the string is nested
- // via the ",string" option.
- if len(s) < 2 || s[len(s)-1] != '"' {
+func unquoteBytes(s []byte) (t []byte, ok bool) {
+ if len(s) < 2 || s[0] != '"' || s[len(s)-1] != '"' {
return
}
s = s[1 : len(s)-1]
- // If there are no unusual characters, no unquoting is needed, so return
- // a slice of the original bytes.
- r := d.safeUnquote
- if r == -1 {
+ // Check for unusual characters. If there are none,
+ // then no unquoting is needed, so return a slice of the
+ // original bytes.
+ r := 0
+ for r < len(s) {
+ c := s[r]
+ if c == '\\' || c == '"' || c < ' ' {
+ break
+ }
+ if c < utf8.RuneSelf {
+ r++
+ continue
+ }
+ rr, size := utf8.DecodeRune(s[r:])
+ if rr == utf8.RuneError && size == 1 {
+ break
+ }
+ r += size
+ }
+ if r == len(s) {
return s, true
}
diff --git a/src/encoding/json/decode_test.go b/src/encoding/json/decode_test.go
index 3c5fd1428f..219e845c7b 100644
--- a/src/encoding/json/decode_test.go
+++ b/src/encoding/json/decode_test.go
@@ -2419,7 +2419,7 @@ func (m *textUnmarshalerString) UnmarshalText(text []byte) error {
return nil
}
-// Test unmarshal to a map, with map key is a user defined type.
+// Test unmarshal to a map, where the map key is a user defined type.
// See golang.org/issues/34437.
func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) {
var p map[textUnmarshalerString]string
@@ -2428,7 +2428,52 @@ func TestUnmarshalMapWithTextUnmarshalerStringKey(t *testing.T) {
}
if _, ok := p["foo"]; !ok {
- t.Errorf(`Key "foo" is not existed in map: %v`, p)
+ t.Errorf(`Key "foo" does not exist in map: %v`, p)
+ }
+}
+
+func TestUnmarshalRescanLiteralMangledUnquote(t *testing.T) {
+ // See golang.org/issues/38105.
+ var p map[textUnmarshalerString]string
+ if err := Unmarshal([]byte(`{"开源":"12345开源"}`), &p); err != nil {
+ t.Fatalf("Unmarshal unexpected error: %v", err)
+ }
+ if _, ok := p["开源"]; !ok {
+ t.Errorf(`Key "开源" does not exist in map: %v`, p)
+ }
+
+ // See golang.org/issues/38126.
+ type T struct {
+ F1 string `json:"F1,string"`
+ }
+ t1 := T{"aaa\tbbb"}
+
+ b, err := Marshal(t1)
+ if err != nil {
+ t.Fatalf("Marshal unexpected error: %v", err)
+ }
+ var t2 T
+ if err := Unmarshal(b, &t2); err != nil {
+ t.Fatalf("Unmarshal unexpected error: %v", err)
+ }
+ if t1 != t2 {
+ t.Errorf("Marshal and Unmarshal roundtrip mismatch: want %q got %q", t1, t2)
+ }
+
+ // See golang.org/issues/39555.
+ input := map[textUnmarshalerString]string{"FOO": "", `"`: ""}
+
+ encoded, err := Marshal(input)
+ if err != nil {
+ t.Fatalf("Marshal unexpected error: %v", err)
+ }
+ var got map[textUnmarshalerString]string
+ if err := Unmarshal(encoded, &got); err != nil {
+ t.Fatalf("Unmarshal unexpected error: %v", err)
+ }
+ want := map[textUnmarshalerString]string{"foo": "", `"`: ""}
+ if !reflect.DeepEqual(want, got) {
+ t.Fatalf("Unexpected roundtrip result:\nwant: %q\ngot: %q", want, got)
}
}
diff --git a/src/encoding/json/encode.go b/src/encoding/json/encode.go
index 9c043593ce..578d551102 100644
--- a/src/encoding/json/encode.go
+++ b/src/encoding/json/encode.go
@@ -635,11 +635,12 @@ func stringEncoder(e *encodeState, v reflect.Value, opts encOpts) {
return
}
if opts.quoted {
- b := make([]byte, 0, v.Len()+2)
- b = append(b, '"')
- b = append(b, []byte(v.String())...)
- b = append(b, '"')
- e.stringBytes(b, opts.escapeHTML)
+ e2 := newEncodeState()
+ // Since we encode the string twice, we only need to escape HTML
+ // the first time.
+ e2.string(v.String(), opts.escapeHTML)
+ e.stringBytes(e2.Bytes(), false)
+ encodeStatePool.Put(e2)
} else {
e.string(v.String(), opts.escapeHTML)
}
diff --git a/src/encoding/json/encode_test.go b/src/encoding/json/encode_test.go
index 5110c7de9b..7290eca06f 100644
--- a/src/encoding/json/encode_test.go
+++ b/src/encoding/json/encode_test.go
@@ -79,37 +79,66 @@ type StringTag struct {
NumberStr Number `json:",string"`
}
-var stringTagExpected = `{
- "BoolStr": "true",
- "IntStr": "42",
- "UintptrStr": "44",
- "StrStr": "\"xzbit\"",
- "NumberStr": "46"
-}`
-
-func TestStringTag(t *testing.T) {
- var s StringTag
- s.BoolStr = true
- s.IntStr = 42
- s.UintptrStr = 44
- s.StrStr = "xzbit"
- s.NumberStr = "46"
- got, err := MarshalIndent(&s, "", " ")
- if err != nil {
- t.Fatal(err)
- }
- if got := string(got); got != stringTagExpected {
- t.Fatalf(" got: %s\nwant: %s\n", got, stringTagExpected)
+func TestRoundtripStringTag(t *testing.T) {
+ tests := []struct {
+ name string
+ in StringTag
+ want string // empty to just test that we roundtrip
+ }{
+ {
+ name: "AllTypes",
+ in: StringTag{
+ BoolStr: true,
+ IntStr: 42,
+ UintptrStr: 44,
+ StrStr: "xzbit",
+ NumberStr: "46",
+ },
+ want: `{
+ "BoolStr": "true",
+ "IntStr": "42",
+ "UintptrStr": "44",
+ "StrStr": "\"xzbit\"",
+ "NumberStr": "46"
+ }`,
+ },
+ {
+ // See golang.org/issues/38173.
+ name: "StringDoubleEscapes",
+ in: StringTag{
+ StrStr: "\b\f\n\r\t\"\\",
+ NumberStr: "0", // just to satisfy the roundtrip
+ },
+ want: `{
+ "BoolStr": "false",
+ "IntStr": "0",
+ "UintptrStr": "0",
+ "StrStr": "\"\\u0008\\u000c\\n\\r\\t\\\"\\\\\"",
+ "NumberStr": "0"
+ }`,
+ },
}
+ for _, test := range tests {
+ t.Run(test.name, func(t *testing.T) {
+ // Indent with a tab prefix to make the multi-line string
+ // literals in the table nicer to read.
+ got, err := MarshalIndent(&test.in, "\t\t\t", "\t")
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got := string(got); got != test.want {
+ t.Fatalf(" got: %s\nwant: %s\n", got, test.want)
+ }
- // Verify that it round-trips.
- var s2 StringTag
- err = NewDecoder(bytes.NewReader(got)).Decode(&s2)
- if err != nil {
- t.Fatalf("Decode: %v", err)
- }
- if !reflect.DeepEqual(s, s2) {
- t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", s, string(got), s2)
+ // Verify that it round-trips.
+ var s2 StringTag
+ if err := Unmarshal(got, &s2); err != nil {
+ t.Fatalf("Decode: %v", err)
+ }
+ if !reflect.DeepEqual(test.in, s2) {
+ t.Fatalf("decode didn't match.\nsource: %#v\nEncoded as:\n%s\ndecode: %#v", test.in, string(got), s2)
+ }
+ })
}
}
diff --git a/src/encoding/json/stream_test.go b/src/encoding/json/stream_test.go
index ebb4f231d1..c9e5334337 100644
--- a/src/encoding/json/stream_test.go
+++ b/src/encoding/json/stream_test.go
@@ -144,14 +144,15 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
},
{
"stringOption", stringOption,
- `{"bar":"\"\u003chtml\u003efoobar\u003c/html\u003e\""}`,
+ `{"bar":"\"\\u003chtml\\u003efoobar\\u003c/html\\u003e\""}`,
`{"bar":"\"<html>foobar</html>\""}`,
},
} {
var buf bytes.Buffer
enc := NewEncoder(&buf)
if err := enc.Encode(tt.v); err != nil {
- t.Fatalf("Encode(%s): %s", tt.name, err)
+ t.Errorf("Encode(%s): %s", tt.name, err)
+ continue
}
if got := strings.TrimSpace(buf.String()); got != tt.wantEscape {
t.Errorf("Encode(%s) = %#q, want %#q", tt.name, got, tt.wantEscape)
@@ -159,7 +160,8 @@ func TestEncoderSetEscapeHTML(t *testing.T) {
buf.Reset()
enc.SetEscapeHTML(false)
if err := enc.Encode(tt.v); err != nil {
- t.Fatalf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err)
+ t.Errorf("SetEscapeHTML(false) Encode(%s): %s", tt.name, err)
+ continue
}
if got := strings.TrimSpace(buf.String()); got != tt.want {
t.Errorf("SetEscapeHTML(false) Encode(%s) = %#q, want %#q",
diff --git a/src/encoding/xml/marshal.go b/src/encoding/xml/marshal.go
index 2440a51e20..0554b0d204 100644
--- a/src/encoding/xml/marshal.go
+++ b/src/encoding/xml/marshal.go
@@ -345,11 +345,8 @@ func (p *printer) createAttrPrefix(url string) string {
if prefix == "" || !isName([]byte(prefix)) || strings.Contains(prefix, ":") {
prefix = "_"
}
- // xmlanything is reserved and any variant of it regardless of
- // case should be matched, so:
- // (('X'|'x') ('M'|'m') ('L'|'l'))
- // See Section 2.3 of https://www.w3.org/TR/REC-xml/
- if len(prefix) >= 3 && strings.EqualFold(prefix[:3], "xml") {
+ if strings.HasPrefix(prefix, "xml") {
+ // xmlanything is reserved.
prefix = "_" + prefix
}
if p.attrNS[prefix] != "" {
@@ -482,8 +479,11 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
xmlname := tinfo.xmlname
if xmlname.name != "" {
start.Name.Space, start.Name.Local = xmlname.xmlns, xmlname.name
- } else if v, ok := xmlname.value(val).Interface().(Name); ok && v.Local != "" {
- start.Name = v
+ } else {
+ fv := xmlname.value(val, dontInitNilPointers)
+ if v, ok := fv.Interface().(Name); ok && v.Local != "" {
+ start.Name = v
+ }
}
}
if start.Name.Local == "" && finfo != nil {
@@ -503,7 +503,7 @@ func (p *printer) marshalValue(val reflect.Value, finfo *fieldInfo, startTemplat
if finfo.flags&fAttr == 0 {
continue
}
- fv := finfo.value(val)
+ fv := finfo.value(val, dontInitNilPointers)
if finfo.flags&fOmitEmpty != 0 && isEmptyValue(fv) {
continue
@@ -806,7 +806,12 @@ func (p *printer) marshalStruct(tinfo *typeInfo, val reflect.Value) error {
if finfo.flags&fAttr != 0 {
continue
}
- vf := finfo.value(val)
+ vf := finfo.value(val, dontInitNilPointers)
+ if !vf.IsValid() {
+ // The field is behind an anonymous struct field that's
+ // nil. Skip it.
+ continue
+ }
switch finfo.flags & fMode {
case fCDATA, fCharData:
diff --git a/src/encoding/xml/marshal_test.go b/src/encoding/xml/marshal_test.go
index 6085ddbba2..31309ef2ca 100644
--- a/src/encoding/xml/marshal_test.go
+++ b/src/encoding/xml/marshal_test.go
@@ -309,6 +309,11 @@ type ChardataEmptyTest struct {
Contents *string `xml:",chardata"`
}
+type PointerAnonFields struct {
+ *MyInt
+ *NamedType
+}
+
type MyMarshalerTest struct {
}
@@ -889,6 +894,18 @@ var marshalTests = []struct {
`</EmbedA>`,
},
+ // Anonymous struct pointer field which is nil
+ {
+ Value: &EmbedB{},
+ ExpectXML: `<EmbedB><FieldB></FieldB></EmbedB>`,
+ },
+
+ // Other kinds of nil anonymous fields
+ {
+ Value: &PointerAnonFields{},
+ ExpectXML: `<PointerAnonFields></PointerAnonFields>`,
+ },
+
// Test that name casing matters
{
Value: &NameCasing{Xy: "mixed", XY: "upper", XyA: "mixedA", XYA: "upperA"},
@@ -2266,30 +2283,6 @@ var encodeTokenTests = []struct {
}},
},
want: `<foo xmlns="space"><bar xmlns="space" xmlns:space="space" space:attr="value">`,
-}, {
- desc: "reserved namespace prefix -- all lower case",
- toks: []Token{
- StartElement{Name{"", "foo"}, []Attr{
- {Name{"http://www.w3.org/2001/xmlSchema-instance", "nil"}, "true"},
- }},
- },
- want: `<foo xmlns:_xmlSchema-instance="http://www.w3.org/2001/xmlSchema-instance" _xmlSchema-instance:nil="true">`,
-}, {
- desc: "reserved namespace prefix -- all upper case",
- toks: []Token{
- StartElement{Name{"", "foo"}, []Attr{
- {Name{"http://www.w3.org/2001/XMLSchema-instance", "nil"}, "true"},
- }},
- },
- want: `<foo xmlns:_XMLSchema-instance="http://www.w3.org/2001/XMLSchema-instance" _XMLSchema-instance:nil="true">`,
-}, {
- desc: "reserved namespace prefix -- all mixed case",
- toks: []Token{
- StartElement{Name{"", "foo"}, []Attr{
- {Name{"http://www.w3.org/2001/XmLSchema-instance", "nil"}, "true"},
- }},
- },
- want: `<foo xmlns:_XmLSchema-instance="http://www.w3.org/2001/XmLSchema-instance" _XmLSchema-instance:nil="true">`,
}}
func TestEncodeToken(t *testing.T) {
diff --git a/src/encoding/xml/read.go b/src/encoding/xml/read.go
index 10a60eed1a..ef5df3f7f6 100644
--- a/src/encoding/xml/read.go
+++ b/src/encoding/xml/read.go
@@ -435,7 +435,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
return UnmarshalError(e)
}
- fv := finfo.value(sv)
+ fv := finfo.value(sv, initNilPointers)
if _, ok := fv.Interface().(Name); ok {
fv.Set(reflect.ValueOf(start.Name))
}
@@ -449,7 +449,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
finfo := &tinfo.fields[i]
switch finfo.flags & fMode {
case fAttr:
- strv := finfo.value(sv)
+ strv := finfo.value(sv, initNilPointers)
if a.Name.Local == finfo.name && (finfo.xmlns == "" || finfo.xmlns == a.Name.Space) {
if err := d.unmarshalAttr(strv, a); err != nil {
return err
@@ -465,7 +465,7 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
}
if !handled && any >= 0 {
finfo := &tinfo.fields[any]
- strv := finfo.value(sv)
+ strv := finfo.value(sv, initNilPointers)
if err := d.unmarshalAttr(strv, a); err != nil {
return err
}
@@ -478,22 +478,22 @@ func (d *Decoder) unmarshal(val reflect.Value, start *StartElement) error {
switch finfo.flags & fMode {
case fCDATA, fCharData:
if !saveData.IsValid() {
- saveData = finfo.value(sv)
+ saveData = finfo.value(sv, initNilPointers)
}
case fComment:
if !saveComment.IsValid() {
- saveComment = finfo.value(sv)
+ saveComment = finfo.value(sv, initNilPointers)
}
case fAny, fAny | fElement:
if !saveAny.IsValid() {
- saveAny = finfo.value(sv)
+ saveAny = finfo.value(sv, initNilPointers)
}
case fInnerXML:
if !saveXML.IsValid() {
- saveXML = finfo.value(sv)
+ saveXML = finfo.value(sv, initNilPointers)
if d.saved == nil {
saveXMLIndex = 0
d.saved = new(bytes.Buffer)
@@ -687,7 +687,7 @@ Loop:
}
if len(finfo.parents) == len(parents) && finfo.name == start.Name.Local {
// It's a perfect match, unmarshal the field.
- return true, d.unmarshal(finfo.value(sv), start)
+ return true, d.unmarshal(finfo.value(sv, initNilPointers), start)
}
if len(finfo.parents) > len(parents) && finfo.parents[len(parents)] == start.Name.Local {
// It's a prefix for the field. Break and recurse
diff --git a/src/encoding/xml/typeinfo.go b/src/encoding/xml/typeinfo.go
index 639952c74a..f30fe58590 100644
--- a/src/encoding/xml/typeinfo.go
+++ b/src/encoding/xml/typeinfo.go
@@ -344,15 +344,25 @@ func (e *TagPathError) Error() string {
return fmt.Sprintf("%s field %q with tag %q conflicts with field %q with tag %q", e.Struct, e.Field1, e.Tag1, e.Field2, e.Tag2)
}
+const (
+ initNilPointers = true
+ dontInitNilPointers = false
+)
+
// value returns v's field value corresponding to finfo.
-// It's equivalent to v.FieldByIndex(finfo.idx), but initializes
-// and dereferences pointers as necessary.
-func (finfo *fieldInfo) value(v reflect.Value) reflect.Value {
+// It's equivalent to v.FieldByIndex(finfo.idx), but when passed
+// initNilPointers, it initializes and dereferences pointers as necessary.
+// When passed dontInitNilPointers and a nil pointer is reached, the function
+// returns a zero reflect.Value.
+func (finfo *fieldInfo) value(v reflect.Value, shouldInitNilPointers bool) reflect.Value {
for i, x := range finfo.idx {
if i > 0 {
t := v.Type()
if t.Kind() == reflect.Ptr && t.Elem().Kind() == reflect.Struct {
if v.IsNil() {
+ if !shouldInitNilPointers {
+ return reflect.Value{}
+ }
v.Set(reflect.New(v.Type().Elem()))
}
v = v.Elem()
diff --git a/src/go.mod b/src/go.mod
index 29407a8a2c..b002f8e516 100644
--- a/src/go.mod
+++ b/src/go.mod
@@ -3,8 +3,8 @@ module std
go 1.15
require (
- golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
- golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
+ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
+ golang.org/x/net v0.0.0-20200707034311-ab3426394381
golang.org/x/sys v0.0.0-20200501145240-bc7a7d42d5c3 // indirect
golang.org/x/text v0.3.3-0.20200430171850-afb9336c4530 // indirect
)
diff --git a/src/go.sum b/src/go.sum
index e154f542f8..528f7e460e 100644
--- a/src/go.sum
+++ b/src/go.sum
@@ -1,9 +1,9 @@
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
-golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79 h1:IaQbIIB2X/Mp/DKctl6ROxz1KyMlKp4uyvL6+kQ7C88=
-golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9 h1:psW17arqaxU48Z5kZ0CQnkZWQJsqcURM6tKiBApRjXI=
+golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5 h1:WQ8q63x+f/zpC8Ac1s9wLElVoHhm32p6tudrU72n1QA=
-golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381 h1:VXak5I6aEWmAXeQjA+QSZzlgNrpq9mjcfDemuexIKsU=
+golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
diff --git a/src/go/build/build.go b/src/go/build/build.go
index 1a122c615f..4a5da308a0 100644
--- a/src/go/build/build.go
+++ b/src/go/build/build.go
@@ -16,7 +16,6 @@ import (
"internal/goversion"
"io"
"io/ioutil"
- "log"
"os"
"os/exec"
pathpkg "path"
@@ -924,7 +923,7 @@ Found:
quoted := spec.Path.Value
path, err := strconv.Unquote(quoted)
if err != nil {
- log.Panicf("%s: parser returned invalid quoted string: <%s>", filename, quoted)
+ panic(fmt.Sprintf("%s: parser returned invalid quoted string: <%s>", filename, quoted))
}
fileImports = append(fileImports, importPos{path, spec.Pos()})
if path == "C" {
diff --git a/src/go/build/build_test.go b/src/go/build/build_test.go
index 7151ba1180..a7f2a3e902 100644
--- a/src/go/build/build_test.go
+++ b/src/go/build/build_test.go
@@ -5,6 +5,7 @@
package build
import (
+ "flag"
"internal/testenv"
"io"
"io/ioutil"
@@ -16,6 +17,14 @@ import (
"testing"
)
+func TestMain(m *testing.M) {
+ flag.Parse()
+ if goTool, err := testenv.GoTool(); err == nil {
+ os.Setenv("PATH", filepath.Dir(goTool)+string(os.PathListSeparator)+os.Getenv("PATH"))
+ }
+ os.Exit(m.Run())
+}
+
func TestMatch(t *testing.T) {
ctxt := Default
what := "default"
diff --git a/src/go/build/deps_test.go b/src/go/build/deps_test.go
index b8be271707..62d6e6296b 100644
--- a/src/go/build/deps_test.go
+++ b/src/go/build/deps_test.go
@@ -20,481 +20,471 @@ import (
"testing"
)
-// pkgDeps defines the expected dependencies between packages in
+// depsRules defines the expected dependencies between packages in
// the Go source tree. It is a statement of policy.
-// Changes should not be made to this map without prior discussion.
-//
-// The map contains two kinds of entries:
-// 1) Lower-case keys are standard import paths and list the
-// allowed imports in that package.
-// 2) Upper-case keys define aliases for package sets, which can then
-// be used as dependencies by other rules.
//
// DO NOT CHANGE THIS DATA TO FIX BUILDS.
+// Existing packages should not have their constraints relaxed
+// without prior discussion.
+// Negative assertions should almost never be removed.
//
-var pkgDeps = map[string][]string{
- // L0 is the lowest level, core, nearly unavoidable packages.
- "errors": {"runtime", "internal/reflectlite"},
- "io": {"errors", "sync", "sync/atomic"},
- "runtime": {"unsafe", "runtime/internal/atomic", "runtime/internal/sys", "runtime/internal/math", "internal/cpu", "internal/bytealg"},
- "runtime/internal/sys": {},
- "runtime/internal/atomic": {"unsafe", "internal/cpu"},
- "runtime/internal/math": {"runtime/internal/sys"},
- "internal/race": {"runtime", "unsafe"},
- "sync": {"internal/race", "runtime", "sync/atomic", "unsafe"},
- "sync/atomic": {"unsafe"},
- "unsafe": {},
- "internal/cpu": {},
- "internal/bytealg": {"unsafe", "internal/cpu"},
- "internal/reflectlite": {"runtime", "unsafe", "internal/unsafeheader"},
- "internal/unsafeheader": {"unsafe"},
-
- "L0": {
- "errors",
- "io",
- "runtime",
- "runtime/internal/atomic",
- "sync",
- "sync/atomic",
- "unsafe",
- "internal/cpu",
- "internal/bytealg",
- "internal/reflectlite",
- },
-
- // L1 adds simple functions and strings processing,
- // but not Unicode tables.
- "math": {"internal/cpu", "unsafe", "math/bits"},
- "math/bits": {"unsafe"},
- "math/cmplx": {"math", "math/bits"},
- "math/rand": {"L0", "math"},
- "strconv": {"L0", "unicode/utf8", "math", "math/bits"},
- "unicode/utf16": {},
- "unicode/utf8": {},
-
- "L1": {
- "L0",
- "math",
- "math/bits",
- "math/cmplx",
- "math/rand",
- "sort",
- "strconv",
- "unicode/utf16",
- "unicode/utf8",
- },
-
- // L2 adds Unicode and strings processing.
- "bufio": {"L0", "unicode/utf8", "bytes", "strings"},
- "bytes": {"L0", "unicode", "unicode/utf8"},
- "path": {"L0", "unicode/utf8", "strings"},
- "strings": {"L0", "unicode", "unicode/utf8"},
- "unicode": {},
-
- "L2": {
- "L1",
- "bufio",
- "bytes",
- "path",
- "strings",
- "unicode",
- },
-
- // 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/internal/subtle", "encoding/binary"},
- "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"},
- "hash/maphash": {"L2", "hash"},
- "image": {"L2", "image/color"}, // interfaces
- "image/color": {"L2"}, // interfaces
- "image/color/palette": {"L2", "image/color"},
- "internal/fmtsort": {"reflect", "sort"},
- "reflect": {"L2", "internal/unsafeheader"},
- "sort": {"internal/reflectlite"},
-
- "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"},
- "crypto/internal/cipherhw": {"crypto/internal/boring"},
- "crypto/tls/fipsonly": {"crypto/internal/boring/fipstls", "crypto/internal/boring/sig"},
-
- "L3": {
- "L2",
- "crypto",
- "crypto/cipher",
- "crypto/internal/boring",
- "crypto/internal/boring/fipstls",
- "crypto/internal/subtle",
- "crypto/subtle",
- "encoding/base32",
- "encoding/base64",
- "encoding/binary",
- "hash",
- "hash/adler32",
- "hash/crc32",
- "hash/crc64",
- "hash/fnv",
- "image",
- "image/color",
- "image/color/palette",
- "internal/fmtsort",
- "internal/oserror",
- "reflect",
- },
-
- // End of linear dependency definitions.
-
- // Operating system access.
- "syscall": {"L0", "internal/oserror", "internal/race", "internal/syscall/windows/sysdll", "internal/unsafeheader", "syscall/js", "unicode/utf16"},
- "syscall/js": {"L0"},
- "internal/oserror": {"L0"},
- "internal/syscall/unix": {"L0", "syscall"},
- "internal/syscall/windows": {"L0", "syscall", "internal/syscall/windows/sysdll", "internal/unsafeheader", "unicode/utf16"},
- "internal/syscall/windows/registry": {"L0", "syscall", "internal/syscall/windows/sysdll", "unicode/utf16"},
- "internal/syscall/execenv": {"L0", "syscall", "internal/syscall/windows", "unicode/utf16"},
- "time": {
- // "L0" without the "io" package:
- "errors",
- "runtime",
- "runtime/internal/atomic",
- "sync",
- "sync/atomic",
- "unsafe",
- // Other time dependencies:
- "internal/syscall/windows/registry",
- "syscall",
- "syscall/js",
- "time/tzdata",
- },
- "time/tzdata": {"L0", "syscall"},
-
- "internal/cfg": {"L0"},
- "internal/poll": {"L0", "internal/oserror", "internal/race", "syscall", "time", "unicode/utf16", "unicode/utf8", "internal/syscall/windows", "internal/syscall/unix"},
- "internal/testlog": {"L0"},
- "os": {"L1", "os", "syscall", "time", "internal/oserror", "internal/poll", "internal/syscall/windows", "internal/syscall/unix", "internal/syscall/execenv", "internal/testlog"},
- "path/filepath": {"L2", "os", "syscall", "internal/syscall/windows"},
- "io/ioutil": {"L2", "os", "path/filepath", "time"},
- "os/exec": {"L2", "os", "context", "path/filepath", "syscall", "internal/syscall/execenv"},
- "os/signal": {"L2", "os", "syscall"},
-
- // OS enables basic operating system functionality,
- // but not direct use of package syscall, nor os/signal.
- "OS": {
- "io/ioutil",
- "os",
- "os/exec",
- "path/filepath",
- "time",
- },
-
- // Formatted I/O: few dependencies (L1) but we must add reflect and internal/fmtsort.
- "fmt": {"L1", "os", "reflect", "internal/fmtsort"},
- "log": {"L1", "os", "fmt", "time"},
-
- // Packages used by testing must be low-level (L2+fmt).
- "regexp": {"L2", "regexp/syntax"},
- "regexp/syntax": {"L2"},
- "runtime/debug": {"L2", "fmt", "io/ioutil", "os", "time"},
- "runtime/pprof": {"L2", "compress/gzip", "context", "encoding/binary", "fmt", "io/ioutil", "os", "syscall", "text/tabwriter", "time"},
- "runtime/trace": {"L0", "context", "fmt"},
- "text/tabwriter": {"L2"},
-
- "testing": {"L2", "flag", "fmt", "internal/race", "io/ioutil", "os", "runtime/debug", "runtime/pprof", "runtime/trace", "time"},
- "testing/iotest": {"L2", "log"},
- "testing/quick": {"L2", "flag", "fmt", "reflect", "time"},
- "internal/obscuretestdata": {"L2", "OS", "encoding/base64"},
- "internal/testenv": {"L2", "OS", "flag", "testing", "syscall", "internal/cfg"},
- "internal/lazyregexp": {"L2", "OS", "regexp"},
- "internal/lazytemplate": {"L2", "OS", "text/template"},
-
- // L4 is defined as L3+fmt+log+time, because in general once
- // you're using L3 packages, use of fmt, log, or time is not a big deal.
- "L4": {
- "L3",
- "fmt",
- "log",
- "time",
- },
-
- // Go parser.
- "go/ast": {"L4", "OS", "go/scanner", "go/token"},
- "go/doc": {"L4", "OS", "go/ast", "go/token", "regexp", "internal/lazyregexp", "text/template"},
- "go/parser": {"L4", "OS", "go/ast", "go/scanner", "go/token"},
- "go/printer": {"L4", "OS", "go/ast", "go/scanner", "go/token", "text/tabwriter"},
- "go/scanner": {"L4", "OS", "go/token"},
- "go/token": {"L4"},
-
- "GOPARSER": {
- "go/ast",
- "go/doc",
- "go/parser",
- "go/printer",
- "go/scanner",
- "go/token",
- },
-
- "go/format": {"L4", "GOPARSER", "internal/format"},
- "internal/format": {"L4", "GOPARSER"},
-
- // Go type checking.
- "go/constant": {"L4", "go/token", "math/big"},
- "go/importer": {"L4", "go/build", "go/internal/gccgoimporter", "go/internal/gcimporter", "go/internal/srcimporter", "go/token", "go/types"},
- "go/internal/gcimporter": {"L4", "OS", "go/build", "go/constant", "go/token", "go/types", "text/scanner"},
- "go/internal/gccgoimporter": {"L4", "OS", "debug/elf", "go/constant", "go/token", "go/types", "internal/xcoff", "text/scanner"},
- "go/internal/srcimporter": {"L4", "OS", "fmt", "go/ast", "go/build", "go/parser", "go/token", "go/types", "path/filepath"},
- "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", "internal/reflectlite", "sync", "sync/atomic", "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", "internal/goroot", "internal/goversion"},
- "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/goroot": {"L4", "OS"},
- "internal/singleflight": {"sync"},
- "internal/trace": {"L4", "OS", "container/heap"},
- "internal/xcoff": {"L4", "OS", "debug/dwarf"},
- "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"},
- "internal/profile": {"L4", "OS", "compress/gzip", "regexp"},
- "testing/internal/testdeps": {"L4", "internal/testlog", "runtime/pprof", "regexp"},
- "text/scanner": {"L4", "OS"},
- "text/template/parse": {"L4"},
-
- "html/template": {
- "L4", "OS", "encoding/json", "html", "text/template",
- "text/template/parse",
- },
- "text/template": {
- "L4", "OS", "net/url", "text/template/parse",
- },
-
- // Cgo.
- // If you add a dependency on CGO, you must add the package to
- // cgoPackages in cmd/dist/test.go.
- "runtime/cgo": {"L0", "C"},
- "CGO": {"C", "runtime/cgo"},
-
- // Fake entry to satisfy the pseudo-import "C"
- // that shows up in programs that use cgo.
- "C": {},
-
- // Race detector/MSan uses cgo.
- "runtime/race": {"C"},
- "runtime/msan": {"C"},
-
- // Plan 9 alone needs io/ioutil and os.
- "os/user": {"L4", "CGO", "io/ioutil", "os", "syscall", "internal/syscall/windows", "internal/syscall/windows/registry"},
-
- // Internal package used only for testing.
- "os/signal/internal/pty": {"CGO", "fmt", "os", "syscall"},
-
- // Basic networking.
- // Because net must be used by any package that wants to
- // do networking portably, it must have a small dependency set: just L0+basic os.
- "net": {
- "L0", "CGO",
- "context", "math/rand", "os", "sort", "syscall", "time",
- "internal/nettrace", "internal/poll", "internal/syscall/unix",
- "internal/syscall/windows", "internal/singleflight", "internal/race",
- "golang.org/x/net/dns/dnsmessage", "golang.org/x/net/lif", "golang.org/x/net/route",
- },
-
- // NET enables use of basic network-related packages.
- "NET": {
- "net",
- "mime",
- "net/textproto",
- "net/url",
- },
-
- // Uses of networking.
- "log/syslog": {"L4", "OS", "net"},
- "net/mail": {"L4", "NET", "OS", "mime"},
- "net/textproto": {"L4", "OS", "net"},
-
- // Core crypto.
- "crypto/aes": {"L3"},
- "crypto/des": {"L3"},
- "crypto/hmac": {"L3"},
- "crypto/internal/randutil": {"io", "sync"},
- "crypto/md5": {"L3"},
- "crypto/rc4": {"L3"},
- "crypto/sha1": {"L3"},
- "crypto/sha256": {"L3"},
- "crypto/sha512": {"L3"},
-
- "CRYPTO": {
- "crypto/aes",
- "crypto/des",
- "crypto/hmac",
- "crypto/internal/randutil",
- "crypto/md5",
- "crypto/rc4",
- "crypto/sha1",
- "crypto/sha256",
- "crypto/sha512",
- "golang.org/x/crypto/chacha20poly1305",
- "golang.org/x/crypto/curve25519",
- "golang.org/x/crypto/poly1305",
- },
-
- // Random byte, number generation.
- // This would be part of core crypto except that it imports
- // math/big, which imports fmt.
- "crypto/rand": {"L4", "CRYPTO", "OS", "math/big", "syscall", "syscall/js", "internal/syscall/unix"},
-
- // Not part of CRYPTO because it imports crypto/rand and crypto/sha512.
- "crypto/ed25519": {"L3", "CRYPTO", "crypto/rand", "crypto/ed25519/internal/edwards25519"},
- "crypto/ed25519/internal/edwards25519": {"encoding/binary"},
-
- // Mathematical crypto: dependencies on fmt (L4) and math/big.
- // We could avoid some of the fmt, but math/big imports fmt anyway.
- "crypto/dsa": {"L4", "CRYPTO", "math/big"},
- "crypto/ecdsa": {
- "L4", "CRYPTO", "crypto/elliptic", "math/big",
- "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1",
- },
- "crypto/elliptic": {"L4", "CRYPTO", "math/big"},
- "crypto/rsa": {"L4", "CRYPTO", "crypto/rand", "math/big"},
-
- "CRYPTO-MATH": {
- "CRYPTO",
- "crypto/dsa",
- "crypto/ecdsa",
- "crypto/elliptic",
- "crypto/rand",
- "crypto/rsa",
- "encoding/asn1",
- "math/big",
- },
-
- // SSL/TLS.
- "crypto/tls": {
- "L4", "CRYPTO-MATH", "OS", "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/hkdf",
- "container/list", "context", "crypto/x509", "encoding/pem", "net", "syscall", "crypto/ed25519",
- },
- "crypto/x509": {
- "L4", "CRYPTO-MATH", "OS", "CGO", "crypto/ed25519",
- "crypto/x509/pkix", "encoding/pem", "encoding/hex", "net", "os/user", "syscall", "net/url",
- "golang.org/x/crypto/cryptobyte", "golang.org/x/crypto/cryptobyte/asn1",
- },
- "crypto/x509/pkix": {"L4", "CRYPTO-MATH", "encoding/hex"},
-
- // Simple net+crypto-aware packages.
- "mime/multipart": {"L4", "OS", "mime", "crypto/rand", "net/textproto", "mime/quotedprintable"},
- "net/smtp": {"L4", "CRYPTO", "NET", "crypto/tls"},
-
- // HTTP, kingpin of dependencies.
- "net/http": {
- "L4", "NET", "OS",
- "compress/gzip",
- "container/list",
- "context",
- "crypto/rand",
- "crypto/tls",
- "golang.org/x/net/http/httpguts",
- "golang.org/x/net/http/httpproxy",
- "golang.org/x/net/http2/hpack",
- "golang.org/x/net/idna",
- "golang.org/x/text/unicode/norm",
- "golang.org/x/text/width",
- "internal/nettrace",
- "mime/multipart",
- "net/http/httptrace",
- "net/http/internal",
- "runtime/debug",
- "syscall/js",
- },
- "net/http/internal": {"L4"},
- "net/http/httptrace": {"context", "crypto/tls", "internal/nettrace", "net", "net/textproto", "reflect", "time"},
-
- // HTTP-using packages.
- "expvar": {"L4", "OS", "encoding/json", "net/http"},
- "net/http/cgi": {"L4", "NET", "OS", "crypto/tls", "net/http", "regexp"},
- "net/http/cookiejar": {"L4", "NET", "net/http"},
- "net/http/fcgi": {"L4", "NET", "OS", "context", "net/http", "net/http/cgi"},
- "net/http/httptest": {
- "L4", "NET", "OS", "crypto/tls", "flag", "net/http", "net/http/internal", "crypto/x509",
- "golang.org/x/net/http/httpguts",
- },
- "net/http/httputil": {"L4", "NET", "OS", "context", "net/http", "net/http/internal", "golang.org/x/net/http/httpguts"},
- "net/http/pprof": {"L4", "OS", "context", "html/template", "net/http", "runtime/pprof", "runtime/trace", "internal/profile"},
- "net/rpc": {"L4", "NET", "encoding/gob", "html/template", "net/http", "go/token"},
- "net/rpc/jsonrpc": {"L4", "NET", "encoding/json", "net/rpc"},
-}
+// The general syntax of a rule is:
+//
+// a, b < c, d;
+//
+// which means c and d come after a and b in the partial order
+// (that is, c and d can import a and b),
+// but doesn't provide a relative order between a vs b or c vs d.
+//
+// The rules can chain together, as in:
+//
+// e < f, g < h;
+//
+// which is equivalent to
+//
+// e < f, g;
+// f, g < h;
+//
+// Except for the special bottom element "NONE", each name
+// must appear exactly once on the right-hand side of a rule.
+// That rule serves as the definition of the allowed dependencies
+// for that name. The definition must appear before any uses
+// of the name on the left-hand side of a rule. (That is, the
+// rules themselves must be ordered according to the partial
+// order, for easier reading by people.)
+//
+// Negative assertions double-check the partial order:
+//
+// i !< j
+//
+// means that it must NOT be the case that i < j.
+// Negative assertions may appear anywhere in the rules,
+// even before i and j have been defined.
+//
+// Comments begin with #.
+//
+// All-caps names are pseudo-names for specific points
+// in the dependency lattice.
+//
+var depsRules = `
+ # No dependencies allowed for any of these packages.
+ NONE
+ < container/list, container/ring,
+ internal/cfg, internal/cpu,
+ internal/goversion, internal/nettrace,
+ unicode/utf8, unicode/utf16, unicode,
+ unsafe;
+
+ # RUNTIME is the core runtime group of packages, all of them very light-weight.
+ internal/cpu, unsafe
+ < internal/bytealg
+ < internal/unsafeheader
+ < runtime/internal/sys
+ < runtime/internal/atomic
+ < runtime/internal/math
+ < runtime
+ < sync/atomic
+ < internal/race
+ < sync
+ < internal/reflectlite
+ < errors
+ < internal/oserror, math/bits
+ < RUNTIME;
+
+ RUNTIME
+ < sort
+ < container/heap;
+
+ RUNTIME
+ < io;
+
+ reflect !< sort;
+
+ # SYSCALL is RUNTIME plus the packages necessary for basic system calls.
+ RUNTIME, unicode/utf8, unicode/utf16, io
+ < internal/syscall/windows/sysdll, syscall/js
+ < syscall
+ < internal/syscall/unix, internal/syscall/windows, internal/syscall/windows/registry
+ < internal/syscall/execenv
+ < SYSCALL;
+
+ # TIME is SYSCALL plus the core packages about time, including context.
+ SYSCALL
+ < time/tzdata
+ < time
+ < context
+ < TIME;
+
+ # MATH is RUNTIME plus the basic math packages.
+ RUNTIME
+ < math
+ < MATH;
+
+ unicode !< math;
+
+ MATH
+ < math/cmplx;
+
+ MATH
+ < math/rand;
+
+ MATH, unicode/utf8
+ < strconv;
+
+ unicode !< strconv;
+
+ # STR is basic string and buffer manipulation.
+ RUNTIME, io, unicode/utf8, unicode/utf16, unicode
+ < bytes, strings
+ < bufio, path;
+
+ bufio, path, strconv
+ < STR;
+
+ # OS is basic OS access, including helpers (path/filepath, os/exec, etc).
+ # OS includes string routines, but those must be layered above package os.
+ # OS does not include reflection.
+ TIME, io, sort
+ < internal/testlog
+ < internal/poll
+ < os
+ < os/signal;
+
+ unicode, fmt !< os, os/signal;
+
+ os/signal, STR
+ < path/filepath
+ < io/ioutil, os/exec
+ < OS;
+
+ reflect !< OS;
+
+ OS
+ < golang.org/x/sys/cpu, internal/goroot;
+
+ # FMT is OS (which includes string routines) plus reflect and fmt.
+ # It does not include package log, which should be avoided in core packages.
+ strconv, unicode
+ < reflect;
+
+ os, reflect
+ < internal/fmtsort
+ < fmt;
+
+ OS, fmt
+ < FMT;
+
+ log !< FMT;
+
+ # Misc packages needing only FMT.
+ FMT
+ < flag,
+ html,
+ mime/quotedprintable,
+ net/internal/socktest,
+ net/url,
+ runtime/debug,
+ runtime/trace,
+ text/scanner,
+ text/tabwriter;
+
+ # encodings
+ # core ones do not use fmt.
+ io, strconv
+ < encoding;
+
+ encoding, reflect
+ < encoding/binary
+ < encoding/base32, encoding/base64;
+
+ fmt !< encoding/base32, encoding/base64;
+
+ FMT, encoding/base32, encoding/base64
+ < encoding/ascii85, encoding/csv, encoding/gob, encoding/hex,
+ encoding/json, encoding/pem, encoding/xml, mime;
+
+ # hashes
+ io
+ < hash
+ < hash/adler32, hash/crc32, hash/crc64, hash/fnv, hash/maphash;
+
+ # math/big
+ FMT, encoding/binary, math/rand
+ < math/big;
+
+ # compression
+ FMT, encoding/binary, hash/adler32, hash/crc32
+ < compress/bzip2, compress/flate, compress/lzw
+ < archive/zip, compress/gzip, compress/zlib;
+
+ # templates
+ FMT
+ < text/template/parse;
+
+ net/url, text/template/parse
+ < text/template
+ < internal/lazytemplate;
+
+ encoding/json, html, text/template
+ < html/template;
+
+ # regexp
+ FMT
+ < regexp/syntax
+ < regexp
+ < internal/lazyregexp;
+
+ # suffix array
+ encoding/binary, regexp
+ < index/suffixarray;
+
+ # executable parsing
+ FMT, encoding/binary, compress/zlib
+ < debug/dwarf
+ < debug/elf, debug/gosym, debug/macho, debug/pe, debug/plan9obj, internal/xcoff
+ < DEBUG;
+
+ # go parser and friends.
+ FMT
+ < go/token
+ < go/scanner
+ < go/ast
+ < go/parser;
+
+ go/parser, text/tabwriter
+ < go/printer
+ < go/format;
+
+ go/parser, internal/lazyregexp, text/template
+ < go/doc;
+
+ math/big, go/token
+ < go/constant;
+
+ container/heap, go/constant, go/parser
+ < go/types;
+
+ go/doc, go/parser, internal/goroot, internal/goversion
+ < go/build;
+
+ DEBUG, go/build, go/types, text/scanner
+ < go/internal/gcimporter, go/internal/gccgoimporter, go/internal/srcimporter
+ < go/importer;
+
+ # databases
+ FMT
+ < database/sql/internal
+ < database/sql/driver
+ < database/sql;
+
+ # images
+ FMT, compress/lzw, compress/zlib
+ < image/color
+ < image, image/color/palette
+ < image/internal/imageutil
+ < image/draw
+ < image/gif, image/jpeg, image/png;
+
+ # cgo, delayed as long as possible.
+ # If you add a dependency on CGO, you must add the package
+ # to cgoPackages in cmd/dist/test.go as well.
+ RUNTIME
+ < C
+ < runtime/cgo
+ < CGO
+ < runtime/race, runtime/msan;
+
+ # Bulk of the standard library must not use cgo.
+ # The prohibition stops at net and os/user.
+ C !< fmt, go/types;
+
+ CGO, OS
+ < plugin;
+
+ CGO, FMT
+ < os/user
+ < archive/tar;
+
+ sync
+ < internal/singleflight;
+
+ os
+ < golang.org/x/net/dns/dnsmessage,
+ golang.org/x/net/lif,
+ golang.org/x/net/route;
+
+ # net is unavoidable when doing any networking,
+ # so large dependencies must be kept out.
+ # This is a long-looking list but most of these
+ # are small with few dependencies.
+ # math/rand should probably be removed at some point.
+ CGO,
+ golang.org/x/net/dns/dnsmessage,
+ golang.org/x/net/lif,
+ golang.org/x/net/route,
+ internal/nettrace,
+ internal/poll,
+ internal/singleflight,
+ internal/race,
+ math/rand,
+ os
+ < net;
+
+ fmt, unicode !< net;
+
+ # NET is net plus net-helper packages.
+ FMT, net
+ < net/textproto;
+
+ mime, net/textproto, net/url
+ < NET;
+
+ # logging - most packages should not import; http and up is allowed
+ FMT
+ < log;
+
+ log !< crypto/tls, database/sql, go/importer, testing;
+
+ FMT, log, net
+ < log/syslog;
+
+ NET, log
+ < net/mail;
+
+ NONE < crypto/internal/boring/sig;
+ sync/atomic < crypto/internal/boring/fipstls;
+
+ encoding/binary, golang.org/x/sys/cpu, hash,
+ FMT, math/big,
+ CGO, crypto/internal/boring/sig, crypto/internal/boring/fipstls
+ < crypto
+ < crypto/subtle
+ < crypto/internal/subtle
+ < crypto/cipher
+ < encoding/asn1
+ < crypto/internal/boring
+ < crypto/aes, crypto/des, crypto/hmac, crypto/md5, crypto/rc4,
+ crypto/sha1, crypto/sha256, crypto/sha512
+ < crypto/rand
+ < crypto/internal/randutil
+ < crypto/ed25519/internal/edwards25519
+ < crypto/ed25519
+ < golang.org/x/crypto/cryptobyte/asn1
+ < golang.org/x/crypto/cryptobyte
+ < golang.org/x/crypto/curve25519
+ < crypto/dsa, crypto/elliptic, crypto/rsa
+ < crypto/ecdsa
+ < CRYPTO-BORING;
+
+ net !< CRYPTO-BORING;
+
+ # TLS, Prince of Dependencies.
+ CGO, CRYPTO-BORING, NET, container/list, encoding/hex, encoding/pem
+ < golang.org/x/crypto/internal/subtle
+ < golang.org/x/crypto/chacha20
+ < golang.org/x/crypto/poly1305
+ < golang.org/x/crypto/chacha20poly1305
+ < golang.org/x/crypto/hkdf
+ < crypto/x509/internal/macOS
+ < crypto/x509/pkix
+ < crypto/x509
+ < crypto/tls;
+
+ crypto/internal/boring/sig, crypto/internal/boring/fipstls
+ < crypto/tls/fipsonly;
+
+ # crypto-aware packages
+
+ NET, crypto/rand, mime/quotedprintable
+ < mime/multipart;
+
+ crypto/tls
+ < net/smtp;
+
+ # HTTP, King of Dependencies.
+
+ FMT
+ < golang.org/x/net/http2/hpack, net/http/internal;
+
+ FMT, NET, container/list, encoding/binary, log
+ < golang.org/x/text/transform
+ < golang.org/x/text/unicode/norm
+ < golang.org/x/text/unicode/bidi
+ < golang.org/x/text/secure/bidirule
+ < golang.org/x/net/idna
+ < golang.org/x/net/http/httpguts, golang.org/x/net/http/httpproxy;
+
+ NET, crypto/tls
+ < net/http/httptrace;
+
+ compress/gzip,
+ golang.org/x/net/http/httpguts,
+ golang.org/x/net/http/httpproxy,
+ golang.org/x/net/http2/hpack,
+ net/http/internal,
+ net/http/httptrace,
+ mime/multipart,
+ log
+ < net/http;
+
+ # HTTP-aware packages
-// isMacro reports whether p is a package dependency macro
-// (uppercase name).
-func isMacro(p string) bool {
- return 'A' <= p[0] && p[0] <= 'Z'
-}
+ encoding/json, net/http
+ < expvar;
-func allowed(pkg string) map[string]bool {
- m := map[string]bool{}
- var allow func(string)
- allow = func(p string) {
- if m[p] {
- return
- }
- m[p] = true // set even for macros, to avoid loop on cycle
+ net/http
+ < net/http/cookiejar, net/http/httputil;
+
+ net/http, flag
+ < net/http/httptest;
+
+ net/http, regexp
+ < net/http/cgi
+ < net/http/fcgi;
+
+ # Profiling
+ FMT, compress/gzip, encoding/binary, text/tabwriter
+ < runtime/pprof;
+
+ OS, compress/gzip, regexp
+ < internal/profile;
+
+ html/template, internal/profile, net/http, runtime/pprof, runtime/trace
+ < net/http/pprof;
+
+ # RPC
+ encoding/gob, encoding/json, go/token, html/template, net/http
+ < net/rpc
+ < net/rpc/jsonrpc;
+
+ # Test-only
+ log
+ < testing/iotest;
+
+ FMT, flag, math/rand
+ < testing/quick;
- // Upper-case names are macro-expanded.
- if isMacro(p) {
- for _, pp := range pkgDeps[p] {
- allow(pp)
- }
- }
- }
- for _, pp := range pkgDeps[pkg] {
- allow(pp)
- }
- return m
-}
+ FMT, flag, runtime/debug, runtime/trace
+ < testing;
+
+ internal/testlog, runtime/pprof, regexp
+ < testing/internal/testdeps;
+
+ OS, flag, testing, internal/cfg
+ < internal/testenv;
+
+ OS, encoding/base64
+ < internal/obscuretestdata;
+
+ CGO, OS, fmt
+ < os/signal/internal/pty;
+
+ NET, testing
+ < golang.org/x/net/nettest;
+
+ FMT, container/heap, math/rand
+ < internal/trace;
+`
// listStdPkgs returns the same list of packages as "go list std".
func listStdPkgs(goroot string) ([]string, error) {
@@ -513,11 +503,11 @@ func listStdPkgs(goroot string) ([]string, error) {
}
name := filepath.ToSlash(path[len(src):])
- if name == "builtin" || name == "cmd" || strings.Contains(name, "golang.org/x/") {
+ if name == "builtin" || name == "cmd" {
return filepath.SkipDir
}
- pkgs = append(pkgs, name)
+ pkgs = append(pkgs, strings.TrimPrefix(name, "vendor/"))
return nil
}
if err := filepath.Walk(src, walkFn); err != nil {
@@ -542,6 +532,7 @@ func TestDependencies(t *testing.T) {
sort.Strings(all)
sawImport := map[string]map[string]bool{} // from package => to package => true
+ policy := depsPolicy(t)
for _, pkg := range all {
imports, err := findImports(pkg)
@@ -552,7 +543,7 @@ func TestDependencies(t *testing.T) {
if sawImport[pkg] == nil {
sawImport[pkg] = map[string]bool{}
}
- ok := allowed(pkg)
+ ok := policy[pkg]
var bad []string
for _, imp := range imports {
sawImport[pkg][imp] = true
@@ -579,26 +570,16 @@ func TestDependencies(t *testing.T) {
}
return ""
}
-
- // Also test some high-level policy goals are being met by not finding
- // these dependency paths:
- badPaths := []struct{ from, to string }{
- {"net", "unicode"},
- {"os", "unicode"},
- }
-
- for _, path := range badPaths {
- if how := depPath(path.from, path.to); how != "" {
- t.Errorf("policy violation: %s", how)
- }
- }
-
}
var buildIgnore = []byte("\n// +build ignore")
func findImports(pkg string) ([]string, error) {
- dir := filepath.Join(Default.GOROOT, "src", pkg)
+ vpkg := pkg
+ if strings.HasPrefix(pkg, "golang.org") {
+ vpkg = "vendor/" + pkg
+ }
+ dir := filepath.Join(Default.GOROOT, "src", vpkg)
files, err := ioutil.ReadDir(dir)
if err != nil {
return nil, err
@@ -641,3 +622,187 @@ func findImports(pkg string) ([]string, error) {
sort.Strings(imports)
return imports, nil
}
+
+// depsPolicy returns a map m such that m[p][d] == true when p can import d.
+func depsPolicy(t *testing.T) map[string]map[string]bool {
+ allowed := map[string]map[string]bool{"NONE": {}}
+ disallowed := [][2][]string{}
+
+ parseDepsRules(t, func(deps []string, op string, users []string) {
+ if op == "!<" {
+ disallowed = append(disallowed, [2][]string{deps, users})
+ return
+ }
+ for _, u := range users {
+ if allowed[u] != nil {
+ t.Errorf("multiple deps lists for %s", u)
+ }
+ allowed[u] = make(map[string]bool)
+ for _, d := range deps {
+ if allowed[d] == nil {
+ t.Errorf("use of %s before its deps list", d)
+ }
+ allowed[u][d] = true
+ }
+ }
+ })
+
+ // Check for missing deps info.
+ for _, deps := range allowed {
+ for d := range deps {
+ if allowed[d] == nil {
+ t.Errorf("missing deps list for %s", d)
+ }
+ }
+ }
+
+ // Complete transitive allowed deps.
+ for k := range allowed {
+ for i := range allowed {
+ for j := range allowed {
+ if i != k && k != j && allowed[i][k] && allowed[k][j] {
+ if i == j {
+ // Can only happen along with a "use of X before deps" error above,
+ // but this error is more specific - it makes clear that reordering the
+ // rules will not be enough to fix the problem.
+ t.Errorf("deps policy cycle: %s < %s < %s", j, k, i)
+ }
+ allowed[i][j] = true
+ }
+ }
+ }
+ }
+
+ // Check negative assertions against completed allowed deps.
+ for _, bad := range disallowed {
+ deps, users := bad[0], bad[1]
+ for _, d := range deps {
+ for _, u := range users {
+ if allowed[u][d] {
+ t.Errorf("deps policy incorrect: assertion failed: %s !< %s", d, u)
+ }
+ }
+ }
+ }
+
+ if t.Failed() {
+ t.FailNow()
+ }
+
+ return allowed
+}
+
+// parseDepsRules parses depsRules, calling save(deps, op, users)
+// for each deps < users or deps !< users rule
+// (op is "<" or "!<").
+func parseDepsRules(t *testing.T, save func(deps []string, op string, users []string)) {
+ p := &depsParser{t: t, lineno: 1, text: depsRules}
+
+ var prev []string
+ var op string
+ for {
+ list, tok := p.nextList()
+ if tok == "" {
+ if prev == nil {
+ break
+ }
+ p.syntaxError("unexpected EOF")
+ }
+ if prev != nil {
+ save(prev, op, list)
+ }
+ prev = list
+ if tok == ";" {
+ prev = nil
+ op = ""
+ continue
+ }
+ if tok != "<" && tok != "!<" {
+ p.syntaxError("missing <")
+ }
+ op = tok
+ }
+}
+
+// A depsParser parses the depsRules syntax described above.
+type depsParser struct {
+ t *testing.T
+ lineno int
+ lastWord string
+ text string
+}
+
+// syntaxError reports a parsing error.
+func (p *depsParser) syntaxError(msg string) {
+ p.t.Fatalf("deps:%d: syntax error: %s near %s", p.lineno, msg, p.lastWord)
+}
+
+// nextList parses and returns a comma-separated list of names.
+func (p *depsParser) nextList() (list []string, token string) {
+ for {
+ tok := p.nextToken()
+ switch tok {
+ case "":
+ if len(list) == 0 {
+ return nil, ""
+ }
+ fallthrough
+ case ",", "<", "!<", ";":
+ p.syntaxError("bad list syntax")
+ }
+ list = append(list, tok)
+
+ tok = p.nextToken()
+ if tok != "," {
+ return list, tok
+ }
+ }
+}
+
+// nextToken returns the next token in the deps rules,
+// one of ";" "," "<" "!<" or a name.
+func (p *depsParser) nextToken() string {
+ for {
+ if p.text == "" {
+ return ""
+ }
+ switch p.text[0] {
+ case ';', ',', '<':
+ t := p.text[:1]
+ p.text = p.text[1:]
+ return t
+
+ case '!':
+ if len(p.text) < 2 || p.text[1] != '<' {
+ p.syntaxError("unexpected token !")
+ }
+ p.text = p.text[2:]
+ return "!<"
+
+ case '#':
+ i := strings.Index(p.text, "\n")
+ if i < 0 {
+ i = len(p.text)
+ }
+ p.text = p.text[i:]
+ continue
+
+ case '\n':
+ p.lineno++
+ fallthrough
+ case ' ', '\t':
+ p.text = p.text[1:]
+ continue
+
+ default:
+ i := strings.IndexAny(p.text, "!;,<#\n \t")
+ if i < 0 {
+ i = len(p.text)
+ }
+ t := p.text[:i]
+ p.text = p.text[i:]
+ p.lastWord = t
+ return t
+ }
+ }
+}
diff --git a/src/go/build/doc.go b/src/go/build/doc.go
index 9633d599f3..2c6f0a83be 100644
--- a/src/go/build/doc.go
+++ b/src/go/build/doc.go
@@ -59,99 +59,15 @@
//
// A build constraint, also known as a build tag, is a line comment that begins
//
-// // +build
+// // +build
//
-// that lists the conditions under which a file should be included in the package.
-// Constraints may appear in any kind of source file (not just Go), but
-// they must appear near the top of the file, preceded
-// only by blank lines and other line comments. These rules mean that in Go
-// files a build constraint must appear before the package clause.
+// that lists the conditions under which a file should be included in the
+// package. Build constraints may also be part of a file's name
+// (for example, source_windows.go will only be included if the target
+// operating system is windows).
//
-// To distinguish build constraints from package documentation, a series of
-// build constraints must be followed by a blank line.
-//
-// A build constraint is evaluated as the OR of space-separated options.
-// Each option evaluates as the AND of its comma-separated terms.
-// Each term consists of letters, digits, underscores, and dots.
-// A term may be negated with a preceding !.
-// For example, the build constraint:
-//
-// // +build linux,386 darwin,!cgo
-//
-// corresponds to the boolean formula:
-//
-// (linux AND 386) OR (darwin AND (NOT cgo))
-//
-// A file may have multiple build constraints. The overall constraint is the AND
-// of the individual constraints. That is, the build constraints:
-//
-// // +build linux darwin
-// // +build amd64
-//
-// corresponds to the boolean formula:
-//
-// (linux OR darwin) AND amd64
-//
-// During a particular build, the following words are satisfied:
-//
-// - the target operating system, as spelled by runtime.GOOS
-// - the target architecture, as spelled by runtime.GOARCH
-// - the compiler being used, either "gc" or "gccgo"
-// - "cgo", if ctxt.CgoEnabled is true
-// - "go1.1", from Go version 1.1 onward
-// - "go1.2", from Go version 1.2 onward
-// - "go1.3", from Go version 1.3 onward
-// - "go1.4", from Go version 1.4 onward
-// - "go1.5", from Go version 1.5 onward
-// - "go1.6", from Go version 1.6 onward
-// - "go1.7", from Go version 1.7 onward
-// - "go1.8", from Go version 1.8 onward
-// - "go1.9", from Go version 1.9 onward
-// - "go1.10", from Go version 1.10 onward
-// - "go1.11", from Go version 1.11 onward
-// - "go1.12", from Go version 1.12 onward
-// - "go1.13", from Go version 1.13 onward
-// - "go1.14", from Go version 1.14 onward
-// - "go1.15", from Go version 1.15 onward
-// - any additional words listed in ctxt.BuildTags
-//
-// There are no build tags for beta or minor releases.
-//
-// If a file's name, after stripping the extension and a possible _test suffix,
-// matches any of the following patterns:
-// *_GOOS
-// *_GOARCH
-// *_GOOS_GOARCH
-// (example: source_windows_amd64.go) where GOOS and GOARCH represent
-// any known operating system and architecture values respectively, then
-// the file is considered to have an implicit build constraint requiring
-// those terms (in addition to any explicit constraints in the file).
-//
-// To keep a file from being considered for the build:
-//
-// // +build ignore
-//
-// (any other unsatisfied word will work as well, but ``ignore'' is conventional.)
-//
-// To build a file only when using cgo, and only on Linux and OS X:
-//
-// // +build linux,cgo darwin,cgo
-//
-// Such a file is usually paired with another file implementing the
-// default functionality for other systems, which in this case would
-// carry the constraint:
-//
-// // +build !linux,!darwin !cgo
-//
-// Naming a file dns_windows.go will cause it to be included only when
-// building the package for Windows; similarly, math_386.s will be included
-// only when building the package for 32-bit x86.
-//
-// Using GOOS=android matches build tags and files as for GOOS=linux
-// in addition to android tags and files.
-//
-// Using GOOS=illumos matches build tags and files as for GOOS=solaris
-// in addition to illumos tags and files.
+// See 'go help buildconstraint'
+// (https://golang.org/cmd/go/#hdr-Build_constraints) for details.
//
// Binary-Only Packages
//
diff --git a/src/go/internal/srcimporter/srcimporter.go b/src/go/internal/srcimporter/srcimporter.go
index daef27c8b9..90bb3a9bc1 100644
--- a/src/go/internal/srcimporter/srcimporter.go
+++ b/src/go/internal/srcimporter/srcimporter.go
@@ -20,6 +20,7 @@ import (
"path/filepath"
"strings"
"sync"
+ _ "unsafe" // for go:linkname
)
// An Importer provides the context for importing packages from source code.
@@ -133,7 +134,7 @@ func (p *Importer) ImportFrom(path, srcDir string, mode types.ImportMode) (*type
// build.Context's VFS.
conf.FakeImportC = true
} else {
- conf.UsesCgo = true
+ setUsesCgo(&conf)
file, err := p.cgo(bp)
if err != nil {
return nil, err
@@ -260,3 +261,6 @@ func (p *Importer) joinPath(elem ...string) string {
}
return filepath.Join(elem...)
}
+
+//go:linkname setUsesCgo go/types.srcimporter_setUsesCgo
+func setUsesCgo(conf *types.Config)
diff --git a/src/go/internal/srcimporter/srcimporter_test.go b/src/go/internal/srcimporter/srcimporter_test.go
index c456b8e26a..102ac43f94 100644
--- a/src/go/internal/srcimporter/srcimporter_test.go
+++ b/src/go/internal/srcimporter/srcimporter_test.go
@@ -5,11 +5,13 @@
package srcimporter
import (
+ "flag"
"go/build"
"go/token"
"go/types"
"internal/testenv"
"io/ioutil"
+ "os"
"path"
"path/filepath"
"runtime"
@@ -18,6 +20,14 @@ import (
"time"
)
+func TestMain(m *testing.M) {
+ flag.Parse()
+ if goTool, err := testenv.GoTool(); err == nil {
+ os.Setenv("PATH", filepath.Dir(goTool)+string(os.PathListSeparator)+os.Getenv("PATH"))
+ }
+ os.Exit(m.Run())
+}
+
const maxTime = 2 * time.Second
var importer = New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
diff --git a/src/go/token/position.go b/src/go/token/position.go
index 3f5a390078..d0dbc2998f 100644
--- a/src/go/token/position.go
+++ b/src/go/token/position.go
@@ -58,8 +58,11 @@ func (pos Position) String() string {
// larger, representation.
//
// The Pos value for a given file is a number in the range [base, base+size],
-// where base and size are specified when adding the file to the file set via
-// AddFile.
+// where base and size are specified when a file is added to the file set.
+// The difference between a Pos value and the corresponding file base
+// corresponds to the byte offset of that position (represented by the Pos value)
+// from the beginning of the file. Thus, the file base offset is the Pos value
+// representing the first byte in the file.
//
// To create the Pos value for a specific source offset (measured in bytes),
// first add the respective file to the current file set using FileSet.AddFile
@@ -364,6 +367,22 @@ func (f *File) Position(p Pos) (pos Position) {
// Methods of file sets are synchronized; multiple goroutines
// may invoke them concurrently.
//
+// The byte offsets for each file in a file set are mapped into
+// distinct (integer) intervals, one interval [base, base+size]
+// per file. Base represents the first byte in the file, and size
+// is the corresponding file size. A Pos value is a value in such
+// an interval. By determining the interval a Pos value belongs
+// to, the file, its file base, and thus the byte offset (position)
+// the Pos value is representing can be computed.
+//
+// When adding a new file, a file base must be provided. That can
+// be any integer value that is past the end of any interval of any
+// file already in the file set. For convenience, FileSet.Base provides
+// such a value, which is simply the end of the Pos interval of the most
+// recently added file, plus one. Unless there is a need to extend an
+// interval later, using the FileSet.Base should be used as argument
+// for FileSet.AddFile.
+//
type FileSet struct {
mutex sync.RWMutex // protects the file set
base int // base offset for the next file
diff --git a/src/go/types/api.go b/src/go/types/api.go
index 7787b88906..1abcd9d951 100644
--- a/src/go/types/api.go
+++ b/src/go/types/api.go
@@ -105,14 +105,14 @@ type Config struct {
// Do not use casually!
FakeImportC bool
- // If UsesCgo is set, the type checker expects the
+ // If go115UsesCgo is set, the type checker expects the
// _cgo_gotypes.go file generated by running cmd/cgo to be
// provided as a package source file. Qualified identifiers
// referring to package C will be resolved to cgo-provided
// declarations within _cgo_gotypes.go.
//
- // It is an error to set both FakeImportC and UsesCgo.
- UsesCgo bool
+ // It is an error to set both FakeImportC and go115UsesCgo.
+ go115UsesCgo bool
// If Error != nil, it is called with each error found
// during type checking; err has dynamic type Error.
@@ -140,6 +140,10 @@ type Config struct {
DisableUnusedImportCheck bool
}
+func srcimporter_setUsesCgo(conf *Config) {
+ conf.go115UsesCgo = true
+}
+
// Info holds result type information for a type-checked package.
// Only the information for which a map is provided is collected.
// If the package has type errors, the collected information may
diff --git a/src/go/types/check.go b/src/go/types/check.go
index a94770ffef..007babdf9d 100644
--- a/src/go/types/check.go
+++ b/src/go/types/check.go
@@ -248,10 +248,10 @@ func (check *Checker) handleBailout(err *error) {
// Files checks the provided files as part of the checker's package.
func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
-var errBadCgo = errors.New("cannot use FakeImportC and UsesCgo together")
+var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
func (check *Checker) checkFiles(files []*ast.File) (err error) {
- if check.conf.FakeImportC && check.conf.UsesCgo {
+ if check.conf.FakeImportC && check.conf.go115UsesCgo {
return errBadCgo
}
diff --git a/src/go/types/resolver.go b/src/go/types/resolver.go
index f80b4ec784..078adc5ec7 100644
--- a/src/go/types/resolver.go
+++ b/src/go/types/resolver.go
@@ -141,10 +141,10 @@ func (check *Checker) importPackage(pos token.Pos, path, dir string) *Package {
}
// no package yet => import it
- if path == "C" && (check.conf.FakeImportC || check.conf.UsesCgo) {
+ if path == "C" && (check.conf.FakeImportC || check.conf.go115UsesCgo) {
imp = NewPackage("C", "C")
imp.fake = true // package scope is not populated
- imp.cgo = check.conf.UsesCgo
+ imp.cgo = check.conf.go115UsesCgo
} else {
// ordinary import
var err error
diff --git a/src/html/template/html.go b/src/html/template/html.go
index 13a0cd0436..356b8298ae 100644
--- a/src/html/template/html.go
+++ b/src/html/template/html.go
@@ -240,8 +240,7 @@ func htmlNameFilter(args ...interface{}) string {
}
s = strings.ToLower(s)
if t := attrType(s); t != contentTypePlain {
- // TODO: Split attr and element name part filters so we can whitelist
- // attributes.
+ // TODO: Split attr and element name part filters so we can recognize known attributes.
return filterFailsafe
}
for _, r := range s {
diff --git a/src/image/gif/writer_test.go b/src/image/gif/writer_test.go
index b619961787..9b15c8d99d 100644
--- a/src/image/gif/writer_test.go
+++ b/src/image/gif/writer_test.go
@@ -657,7 +657,6 @@ func TestEncodeWrappedImage(t *testing.T) {
}
func BenchmarkEncode(b *testing.B) {
- bo := image.Rect(0, 0, 640, 480)
rnd := rand.New(rand.NewSource(123))
// Restrict to a 256-color paletted image to avoid quantization path.
@@ -671,10 +670,8 @@ func BenchmarkEncode(b *testing.B) {
}
}
img := image.NewPaletted(image.Rect(0, 0, 640, 480), palette)
- for y := bo.Min.Y; y < bo.Max.Y; y++ {
- for x := bo.Min.X; x < bo.Max.X; x++ {
- img.Set(x, y, palette[rnd.Intn(256)])
- }
+ for i := range img.Pix {
+ img.Pix[i] = uint8(rnd.Intn(256))
}
b.SetBytes(640 * 480 * 4)
diff --git a/src/image/png/reader.go b/src/image/png/reader.go
index 5521b39bb0..910520bd4b 100644
--- a/src/image/png/reader.go
+++ b/src/image/png/reader.go
@@ -862,8 +862,7 @@ func (d *decoder) parseIEND(length uint32) error {
func (d *decoder) parseChunk() error {
// Read the length and chunk type.
- n, err := io.ReadFull(d.r, d.tmp[:8])
- if err != nil {
+ if _, err := io.ReadFull(d.r, d.tmp[:8]); err != nil {
return err
}
length := binary.BigEndian.Uint32(d.tmp[:4])
@@ -920,7 +919,7 @@ func (d *decoder) parseChunk() error {
// Ignore this chunk (of a known length).
var ignored [4096]byte
for length > 0 {
- n, err = io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
+ n, err := io.ReadFull(d.r, ignored[:min(len(ignored), int(length))])
if err != nil {
return err
}
diff --git a/src/internal/cfg/cfg.go b/src/internal/cfg/cfg.go
index e40b7b4d1a..bdbe9df3e7 100644
--- a/src/internal/cfg/cfg.go
+++ b/src/internal/cfg/cfg.go
@@ -33,7 +33,6 @@ const KnownEnv = `
GCCGO
GO111MODULE
GO386
- GOAMD64
GOARCH
GOARM
GOBIN
diff --git a/src/internal/poll/copy_file_range_linux.go b/src/internal/poll/copy_file_range_linux.go
index 98210cc6cf..604607f774 100644
--- a/src/internal/poll/copy_file_range_linux.go
+++ b/src/internal/poll/copy_file_range_linux.go
@@ -88,6 +88,12 @@ func copyFileRange(dst, src *FD, max int) (written int64, err error) {
return 0, err
}
defer src.readUnlock()
- n, err := unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
+ var n int
+ for {
+ n, err = unix.CopyFileRange(src.Sysfd, nil, dst.Sysfd, nil, max, 0)
+ if err != syscall.EINTR {
+ break
+ }
+ }
return int64(n), err
}
diff --git a/src/internal/poll/fd_plan9.go b/src/internal/poll/fd_plan9.go
index e57e0419c5..0b5b937533 100644
--- a/src/internal/poll/fd_plan9.go
+++ b/src/internal/poll/fd_plan9.go
@@ -7,6 +7,7 @@ package poll
import (
"errors"
"io"
+ "sync"
"sync/atomic"
"time"
)
@@ -24,6 +25,8 @@ type FD struct {
Destroy func()
// deadlines
+ rmu sync.Mutex
+ wmu sync.Mutex
raio *asyncIO
waio *asyncIO
rtimer *time.Timer
@@ -59,9 +62,6 @@ func (fd *FD) Close() error {
// Read implements io.Reader.
func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
- if fd.rtimedout.isSet() {
- return 0, ErrDeadlineExceeded
- }
if err := fd.readLock(); err != nil {
return 0, err
}
@@ -69,7 +69,13 @@ func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
if len(b) == 0 {
return 0, nil
}
+ fd.rmu.Lock()
+ if fd.rtimedout.isSet() {
+ fd.rmu.Unlock()
+ return 0, ErrDeadlineExceeded
+ }
fd.raio = newAsyncIO(fn, b)
+ fd.rmu.Unlock()
n, err := fd.raio.Wait()
fd.raio = nil
if isHangup(err) {
@@ -83,14 +89,17 @@ func (fd *FD) Read(fn func([]byte) (int, error), b []byte) (int, error) {
// Write implements io.Writer.
func (fd *FD) Write(fn func([]byte) (int, error), b []byte) (int, error) {
- if fd.wtimedout.isSet() {
- return 0, ErrDeadlineExceeded
- }
if err := fd.writeLock(); err != nil {
return 0, err
}
defer fd.writeUnlock()
+ fd.wmu.Lock()
+ if fd.wtimedout.isSet() {
+ fd.wmu.Unlock()
+ return 0, ErrDeadlineExceeded
+ }
fd.waio = newAsyncIO(fn, b)
+ fd.wmu.Unlock()
n, err := fd.waio.Wait()
fd.waio = nil
if isInterrupted(err) {
@@ -117,9 +126,13 @@ func (fd *FD) SetWriteDeadline(t time.Time) error {
func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
d := t.Sub(time.Now())
if mode == 'r' || mode == 'r'+'w' {
+ fd.rmu.Lock()
+ defer fd.rmu.Unlock()
fd.rtimedout.setFalse()
}
if mode == 'w' || mode == 'r'+'w' {
+ fd.wmu.Lock()
+ defer fd.wmu.Unlock()
fd.wtimedout.setFalse()
}
if t.IsZero() || d < 0 {
@@ -140,18 +153,22 @@ func setDeadlineImpl(fd *FD, t time.Time, mode int) error {
// Interrupt I/O operation once timer has expired
if mode == 'r' || mode == 'r'+'w' {
fd.rtimer = time.AfterFunc(d, func() {
+ fd.rmu.Lock()
fd.rtimedout.setTrue()
if fd.raio != nil {
fd.raio.Cancel()
}
+ fd.rmu.Unlock()
})
}
if mode == 'w' || mode == 'r'+'w' {
fd.wtimer = time.AfterFunc(d, func() {
+ fd.wmu.Lock()
fd.wtimedout.setTrue()
if fd.waio != nil {
fd.waio.Cancel()
}
+ fd.wmu.Unlock()
})
}
}
diff --git a/src/internal/poll/fd_unix.go b/src/internal/poll/fd_unix.go
index 4716d58a6e..4872fa9851 100644
--- a/src/internal/poll/fd_unix.go
+++ b/src/internal/poll/fd_unix.go
@@ -8,7 +8,6 @@ package poll
import (
"io"
- "runtime"
"sync/atomic"
"syscall"
)
@@ -153,7 +152,7 @@ func (fd *FD) Read(p []byte) (int, error) {
p = p[:maxRW]
}
for {
- n, err := syscall.Read(fd.Sysfd, p)
+ n, err := ignoringEINTR(syscall.Read, fd.Sysfd, p)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -161,12 +160,6 @@ func (fd *FD) Read(p []byte) (int, error) {
continue
}
}
-
- // On MacOS we can see EINTR here if the user
- // pressed ^Z. See issue #22838.
- if runtime.GOOS == "darwin" && err == syscall.EINTR {
- continue
- }
}
err = fd.eofError(n, err)
return n, err
@@ -184,7 +177,16 @@ func (fd *FD) Pread(p []byte, off int64) (int, error) {
if fd.IsStream && len(p) > maxRW {
p = p[:maxRW]
}
- n, err := syscall.Pread(fd.Sysfd, p, off)
+ var (
+ n int
+ err error
+ )
+ for {
+ n, err = syscall.Pread(fd.Sysfd, p, off)
+ if err != syscall.EINTR {
+ break
+ }
+ }
if err != nil {
n = 0
}
@@ -205,6 +207,9 @@ func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
for {
n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
if err != nil {
+ if err == syscall.EINTR {
+ continue
+ }
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -229,6 +234,9 @@ func (fd *FD) ReadMsg(p []byte, oob []byte) (int, int, int, syscall.Sockaddr, er
for {
n, oobn, flags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, 0)
if err != nil {
+ if err == syscall.EINTR {
+ continue
+ }
// TODO(dfc) should n and oobn be set to 0
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -256,7 +264,7 @@ func (fd *FD) Write(p []byte) (int, error) {
if fd.IsStream && max-nn > maxRW {
max = nn + maxRW
}
- n, err := syscall.Write(fd.Sysfd, p[nn:max])
+ n, err := ignoringEINTR(syscall.Write, fd.Sysfd, p[nn:max])
if n > 0 {
nn += n
}
@@ -293,6 +301,9 @@ func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
max = nn + maxRW
}
n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
+ if err == syscall.EINTR {
+ continue
+ }
if n > 0 {
nn += n
}
@@ -319,6 +330,9 @@ func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
}
for {
err := syscall.Sendto(fd.Sysfd, p, 0, sa)
+ if err == syscall.EINTR {
+ continue
+ }
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
@@ -342,6 +356,9 @@ func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, err
}
for {
n, err := syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
+ if err == syscall.EINTR {
+ continue
+ }
if err == syscall.EAGAIN && fd.pd.pollable() {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
@@ -370,6 +387,8 @@ func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
return s, rsa, "", err
}
switch err {
+ case syscall.EINTR:
+ continue
case syscall.EAGAIN:
if fd.pd.pollable() {
if err = fd.pd.waitRead(fd.isFile); err == nil {
@@ -404,7 +423,7 @@ func (fd *FD) ReadDirent(buf []byte) (int, error) {
}
defer fd.decref()
for {
- n, err := syscall.ReadDirent(fd.Sysfd, buf)
+ n, err := ignoringEINTR(syscall.ReadDirent, fd.Sysfd, buf)
if err != nil {
n = 0
if err == syscall.EAGAIN && fd.pd.pollable() {
@@ -460,7 +479,7 @@ func DupCloseOnExec(fd int) (int, string, error) {
return dupCloseOnExecOld(fd)
}
-// dupCloseOnExecUnixOld is the traditional way to dup an fd and
+// dupCloseOnExecOld 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()
@@ -495,7 +514,7 @@ func (fd *FD) WriteOnce(p []byte) (int, error) {
return 0, err
}
defer fd.writeUnlock()
- return syscall.Write(fd.Sysfd, p)
+ return ignoringEINTR(syscall.Write, fd.Sysfd, p)
}
// RawRead invokes the user-defined function f for a read operation.
@@ -535,3 +554,19 @@ func (fd *FD) RawWrite(f func(uintptr) bool) error {
}
}
}
+
+// ignoringEINTR makes a function call and repeats it if it returns
+// an EINTR error. This appears to be required even though we install
+// all signal handlers with SA_RESTART: see #22838, #38033, #38836.
+// Also #20400 and #36644 are issues in which a signal handler is
+// installed without setting SA_RESTART. None of these are the common case,
+// but there are enough of them that it seems that we can't avoid
+// an EINTR loop.
+func ignoringEINTR(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
+ for {
+ n, err := fn(fd, p)
+ if err != syscall.EINTR {
+ return n, err
+ }
+ }
+}
diff --git a/src/internal/poll/fd_writev_unix.go b/src/internal/poll/fd_writev_unix.go
index 86af795b5a..daeec96c38 100644
--- a/src/internal/poll/fd_writev_unix.go
+++ b/src/internal/poll/fd_writev_unix.go
@@ -12,9 +12,18 @@ import (
)
func writev(fd int, iovecs []syscall.Iovec) (uintptr, error) {
- r, _, e := syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
+ var (
+ r uintptr
+ e syscall.Errno
+ )
+ for {
+ r, _, e = syscall.Syscall(syscall.SYS_WRITEV, uintptr(fd), uintptr(unsafe.Pointer(&iovecs[0])), uintptr(len(iovecs)))
+ if e != syscall.EINTR {
+ break
+ }
+ }
if e != 0 {
- return r, syscall.Errno(e)
+ return r, e
}
return r, nil
}
diff --git a/src/internal/poll/sendfile_bsd.go b/src/internal/poll/sendfile_bsd.go
index 40ae3468b0..a24e41dcaa 100644
--- a/src/internal/poll/sendfile_bsd.go
+++ b/src/internal/poll/sendfile_bsd.go
@@ -35,6 +35,9 @@ func SendFile(dstFD *FD, src int, pos, remain int64) (int64, error) {
} else if n == 0 && err1 == nil {
break
}
+ if err1 == syscall.EINTR {
+ continue
+ }
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
continue
diff --git a/src/internal/poll/sendfile_linux.go b/src/internal/poll/sendfile_linux.go
index 8e938065f1..d64283007d 100644
--- a/src/internal/poll/sendfile_linux.go
+++ b/src/internal/poll/sendfile_linux.go
@@ -32,6 +32,9 @@ func SendFile(dstFD *FD, src int, remain int64) (int64, error) {
} else if n == 0 && err1 == nil {
break
}
+ if err1 == syscall.EINTR {
+ continue
+ }
if err1 == syscall.EAGAIN {
if err1 = dstFD.pd.waitWrite(dstFD.isFile); err1 == nil {
continue
diff --git a/src/internal/poll/splice_linux.go b/src/internal/poll/splice_linux.go
index 5b17ae8551..01baf14ed7 100644
--- a/src/internal/poll/splice_linux.go
+++ b/src/internal/poll/splice_linux.go
@@ -87,6 +87,9 @@ func spliceDrain(pipefd int, sock *FD, max int) (int, error) {
}
for {
n, err := splice(pipefd, sock.Sysfd, max, spliceNonblock)
+ if err == syscall.EINTR {
+ continue
+ }
if err != syscall.EAGAIN {
return n, err
}
diff --git a/src/internal/poll/writev.go b/src/internal/poll/writev.go
index 6050d1f642..305e2fd209 100644
--- a/src/internal/poll/writev.go
+++ b/src/internal/poll/writev.go
@@ -68,7 +68,10 @@ func (fd *FD) Writev(v *[][]byte) (int64, error) {
iovecs[i] = syscall.Iovec{}
}
if err != nil {
- if err.(syscall.Errno) == syscall.EAGAIN {
+ if err == syscall.EINTR {
+ continue
+ }
+ if err == syscall.EAGAIN {
if err = fd.pd.waitWrite(fd.isFile); err == nil {
continue
}
diff --git a/src/internal/trace/writer.go b/src/internal/trace/writer.go
index af5fec84fd..dd0b9f104e 100644
--- a/src/internal/trace/writer.go
+++ b/src/internal/trace/writer.go
@@ -1,3 +1,7 @@
+// 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 trace
import "bytes"
diff --git a/src/io/ioutil/ioutil.go b/src/io/ioutil/ioutil.go
index b1cb841468..acc6ec3a40 100644
--- a/src/io/ioutil/ioutil.go
+++ b/src/io/ioutil/ioutil.go
@@ -75,7 +75,7 @@ func ReadFile(filename string) ([]byte, error) {
// WriteFile writes data to a file named by filename.
// If the file does not exist, WriteFile creates it with permissions perm
-// (before umask); otherwise WriteFile truncates it before writing.
+// (before umask); otherwise WriteFile truncates it before writing, without changing permissions.
func WriteFile(filename string, data []byte, perm os.FileMode) error {
f, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, perm)
if err != nil {
diff --git a/src/make.bat b/src/make.bat
index f7955ec88a..277a34d5d7 100644
--- a/src/make.bat
+++ b/src/make.bat
@@ -1,153 +1,152 @@
-:: 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.
-
-:: Environment variables that control make.bat:
-::
-:: GOROOT_FINAL: The expected final Go root, baked into binaries.
-:: The default is the location of the Go tree during the build.
-::
-:: GOHOSTARCH: The architecture for host tools (compilers and
-:: binaries). Binaries of this type must be executable on the current
-:: system, so the only common reason to set this is to set
-:: GOHOSTARCH=386 on an amd64 machine.
-::
-:: GOARCH: The target architecture for installed packages and tools.
-::
-:: GOOS: The target operating system for installed packages and tools.
-::
-:: GO_GCFLAGS: Additional go tool compile arguments to use when
-:: building the packages and commands.
-::
-:: GO_LDFLAGS: Additional go tool link arguments to use when
-:: building the commands.
-::
-:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
-:: to include all cgo related files, .c and .go file with "cgo"
-:: build directive, in the build. Set it to 0 to ignore them.
-::
-:: CC: Command line to run to compile C code for GOHOSTARCH.
-:: Default is "gcc".
-::
-:: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
-:: This is used by cgo. Default is CC.
-::
-:: FC: Command line to run to compile Fortran code.
-:: This is used by cgo. Default is "gfortran".
-
-@echo off
-
-:: Keep environment variables within this script
-:: unless invoked with --no-local.
-if x%1==x--no-local goto nolocal
-if x%2==x--no-local goto nolocal
-if x%3==x--no-local goto nolocal
-if x%4==x--no-local goto nolocal
-setlocal
-:nolocal
-
-set GOENV=off
-set GOBUILDFAIL=0
-set GOFLAGS=
-set GO111MODULE=
-
-if exist make.bat goto ok
-echo Must run make.bat from Go src directory.
-goto fail
-:ok
-
-:: Clean old generated file that will cause problems in the build.
-del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
-
-:: Set GOROOT for build.
-cd ..
-set GOROOT_TEMP=%CD%
-set GOROOT=
-cd src
-set vflag=
-if x%1==x-v set vflag=-v
-if x%2==x-v set vflag=-v
-if x%3==x-v set vflag=-v
-if x%4==x-v set vflag=-v
-
-if not exist ..\bin\tool mkdir ..\bin\tool
-
-:: Calculating GOROOT_BOOTSTRAP
-if not "x%GOROOT_BOOTSTRAP%"=="x" goto bootstrapset
-for /f "tokens=*" %%g in ('where go 2^>nul') do (
- if "x%GOROOT_BOOTSTRAP%"=="x" (
- for /f "tokens=*" %%i in ('%%g env GOROOT 2^>nul') do (
- if /I not %%i==%GOROOT_TEMP% (
- set GOROOT_BOOTSTRAP=%%i
- )
- )
- )
-)
-if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4
-
-:bootstrapset
-if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail
-set GOROOT=%GOROOT_TEMP%
-set GOROOT_TEMP=
-
-echo Building Go cmd/dist using %GOROOT_BOOTSTRAP%
-if x%vflag==x-v echo cmd/dist
-setlocal
-set GOROOT=%GOROOT_BOOTSTRAP%
-set GOOS=
-set GOARCH=
-set GOBIN=
-set GO111MODULE=off
-"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist
-endlocal
-if errorlevel 1 goto fail
-.\cmd\dist\dist.exe env -w -p >env.bat
-if errorlevel 1 goto fail
-call env.bat
-del env.bat
-if x%vflag==x-v echo.
-
-if x%1==x--dist-tool goto copydist
-if x%2==x--dist-tool goto copydist
-if x%3==x--dist-tool goto copydist
-if x%4==x--dist-tool goto copydist
-
-set buildall=-a
-if x%1==x--no-clean set buildall=
-if x%2==x--no-clean set buildall=
-if x%3==x--no-clean set buildall=
-if x%4==x--no-clean set buildall=
-if x%1==x--no-banner set buildall=%buildall% --no-banner
-if x%2==x--no-banner set buildall=%buildall% --no-banner
-if x%3==x--no-banner set buildall=%buildall% --no-banner
-if x%4==x--no-banner set buildall=%buildall% --no-banner
-
-:: Run dist bootstrap to complete make.bash.
-:: Bootstrap installs a proper cmd/dist, built with the new toolchain.
-:: Throw ours, built with Go 1.4, away after bootstrap.
-.\cmd\dist\dist.exe bootstrap %vflag% %buildall%
-if errorlevel 1 goto fail
-del .\cmd\dist\dist.exe
-goto end
-
-:: DO NOT ADD ANY NEW CODE HERE.
-:: The bootstrap+del above are the final step of make.bat.
-:: If something must be added, add it to cmd/dist's cmdbootstrap,
-:: to avoid needing three copies in three different shell languages
-:: (make.bash, make.bat, make.rc).
-
-:copydist
-mkdir "%GOTOOLDIR%" 2>NUL
-copy cmd\dist\dist.exe "%GOTOOLDIR%\"
-goto end
-
-:bootstrapfail
-echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe
-echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go 1.4.
-
-:fail
-set GOBUILDFAIL=1
-if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
-
-:end
-
+:: 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.
+
+:: Environment variables that control make.bat:
+::
+:: GOROOT_FINAL: The expected final Go root, baked into binaries.
+:: The default is the location of the Go tree during the build.
+::
+:: GOHOSTARCH: The architecture for host tools (compilers and
+:: binaries). Binaries of this type must be executable on the current
+:: system, so the only common reason to set this is to set
+:: GOHOSTARCH=386 on an amd64 machine.
+::
+:: GOARCH: The target architecture for installed packages and tools.
+::
+:: GOOS: The target operating system for installed packages and tools.
+::
+:: GO_GCFLAGS: Additional go tool compile arguments to use when
+:: building the packages and commands.
+::
+:: GO_LDFLAGS: Additional go tool link arguments to use when
+:: building the commands.
+::
+:: CGO_ENABLED: Controls cgo usage during the build. Set it to 1
+:: to include all cgo related files, .c and .go file with "cgo"
+:: build directive, in the build. Set it to 0 to ignore them.
+::
+:: CC: Command line to run to compile C code for GOHOSTARCH.
+:: Default is "gcc".
+::
+:: CC_FOR_TARGET: Command line to run compile C code for GOARCH.
+:: This is used by cgo. Default is CC.
+::
+:: FC: Command line to run to compile Fortran code.
+:: This is used by cgo. Default is "gfortran".
+
+@echo off
+
+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+if x%3==x--no-local goto nolocal
+if x%4==x--no-local goto nolocal
+setlocal
+:nolocal
+
+set GOENV=off
+set GOBUILDFAIL=0
+set GOFLAGS=
+set GO111MODULE=
+
+if exist make.bat goto ok
+echo Must run make.bat from Go src directory.
+goto fail
+:ok
+
+:: Clean old generated file that will cause problems in the build.
+del /F ".\pkg\runtime\runtime_defs.go" 2>NUL
+
+:: Set GOROOT for build.
+cd ..
+set GOROOT_TEMP=%CD%
+set GOROOT=
+cd src
+set vflag=
+if x%1==x-v set vflag=-v
+if x%2==x-v set vflag=-v
+if x%3==x-v set vflag=-v
+if x%4==x-v set vflag=-v
+
+if not exist ..\bin\tool mkdir ..\bin\tool
+
+:: Calculating GOROOT_BOOTSTRAP
+if not "x%GOROOT_BOOTSTRAP%"=="x" goto bootstrapset
+for /f "tokens=*" %%g in ('where go 2^>nul') do (
+ if "x%GOROOT_BOOTSTRAP%"=="x" (
+ for /f "tokens=*" %%i in ('%%g env GOROOT 2^>nul') do (
+ if /I not %%i==%GOROOT_TEMP% (
+ set GOROOT_BOOTSTRAP=%%i
+ )
+ )
+ )
+)
+if "x%GOROOT_BOOTSTRAP%"=="x" set GOROOT_BOOTSTRAP=%HOMEDRIVE%%HOMEPATH%\Go1.4
+
+:bootstrapset
+if not exist "%GOROOT_BOOTSTRAP%\bin\go.exe" goto bootstrapfail
+set GOROOT=%GOROOT_TEMP%
+set GOROOT_TEMP=
+
+echo Building Go cmd/dist using %GOROOT_BOOTSTRAP%
+if x%vflag==x-v echo cmd/dist
+setlocal
+set GOROOT=%GOROOT_BOOTSTRAP%
+set GOOS=
+set GOARCH=
+set GOBIN=
+set GO111MODULE=off
+"%GOROOT_BOOTSTRAP%\bin\go.exe" build -o cmd\dist\dist.exe .\cmd\dist
+endlocal
+if errorlevel 1 goto fail
+.\cmd\dist\dist.exe env -w -p >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+if x%vflag==x-v echo.
+
+if x%1==x--dist-tool goto copydist
+if x%2==x--dist-tool goto copydist
+if x%3==x--dist-tool goto copydist
+if x%4==x--dist-tool goto copydist
+
+set buildall=-a
+if x%1==x--no-clean set buildall=
+if x%2==x--no-clean set buildall=
+if x%3==x--no-clean set buildall=
+if x%4==x--no-clean set buildall=
+if x%1==x--no-banner set buildall=%buildall% --no-banner
+if x%2==x--no-banner set buildall=%buildall% --no-banner
+if x%3==x--no-banner set buildall=%buildall% --no-banner
+if x%4==x--no-banner set buildall=%buildall% --no-banner
+
+:: Run dist bootstrap to complete make.bash.
+:: Bootstrap installs a proper cmd/dist, built with the new toolchain.
+:: Throw ours, built with Go 1.4, away after bootstrap.
+.\cmd\dist\dist.exe bootstrap %vflag% %buildall%
+if errorlevel 1 goto fail
+del .\cmd\dist\dist.exe
+goto end
+
+:: DO NOT ADD ANY NEW CODE HERE.
+:: The bootstrap+del above are the final step of make.bat.
+:: If something must be added, add it to cmd/dist's cmdbootstrap,
+:: to avoid needing three copies in three different shell languages
+:: (make.bash, make.bat, make.rc).
+
+:copydist
+mkdir "%GOTOOLDIR%" 2>NUL
+copy cmd\dist\dist.exe "%GOTOOLDIR%\"
+goto end
+
+:bootstrapfail
+echo ERROR: Cannot find %GOROOT_BOOTSTRAP%\bin\go.exe
+echo Set GOROOT_BOOTSTRAP to a working Go tree ^>= Go 1.4.
+
+:fail
+set GOBUILDFAIL=1
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
+
+:end
diff --git a/src/math/big/link_test.go b/src/math/big/link_test.go
index ad4359cee0..2212bd444f 100644
--- a/src/math/big/link_test.go
+++ b/src/math/big/link_test.go
@@ -20,8 +20,9 @@ func TestLinkerGC(t *testing.T) {
t.Skip("skipping in short mode")
}
t.Parallel()
+ tmp := t.TempDir()
goBin := testenv.GoToolPath(t)
- goFile := filepath.Join(t.TempDir(), "x.go")
+ goFile := filepath.Join(tmp, "x.go")
file := []byte(`package main
import _ "math/big"
func main() {}
@@ -30,13 +31,13 @@ func main() {}
t.Fatal(err)
}
cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
- cmd.Dir = t.TempDir()
+ cmd.Dir = tmp
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("compile: %v, %s", err, out)
}
cmd = exec.Command(goBin, "tool", "nm", "x.exe")
- cmd.Dir = t.TempDir()
+ cmd.Dir = tmp
nm, err := cmd.CombinedOutput()
if err != nil {
t.Fatalf("nm: %v, %s", err, nm)
diff --git a/src/math/exp_amd64.s b/src/math/exp_amd64.s
index 525745d66c..b3e1c22d04 100644
--- a/src/math/exp_amd64.s
+++ b/src/math/exp_amd64.s
@@ -8,7 +8,7 @@
// methods of elementary functions suitable for SIMD computation", Proc.
// of International Supercomputing Conference 2010 (ISC'10), pp. 25 -- 32
// (May 2010). The paper is available at
-// https://www.springerlink.com/content/340228x165742104/
+// https://link.springer.com/article/10.1007/s00450-010-0108-2
//
// The original code and the constants below are from the author's
// implementation available at http://freshmeat.net/projects/sleef.
diff --git a/src/net/http/cgi/host.go b/src/net/http/cgi/host.go
index a038575480..863f40638a 100644
--- a/src/net/http/cgi/host.go
+++ b/src/net/http/cgi/host.go
@@ -29,6 +29,8 @@ import (
"runtime"
"strconv"
"strings"
+
+ "golang.org/x/net/http/httpguts"
)
var trailingPort = regexp.MustCompile(`:([0-9]+)$`)
@@ -277,7 +279,10 @@ func (h *Handler) ServeHTTP(rw http.ResponseWriter, req *http.Request) {
continue
}
header, val := parts[0], parts[1]
- header = textproto.TrimString(header)
+ if !httpguts.ValidHeaderFieldName(header) {
+ h.printf("cgi: invalid header name: %q", header)
+ continue
+ }
val = textproto.TrimString(val)
switch {
case header == "Status":
diff --git a/src/net/http/fs.go b/src/net/http/fs.go
index f95f2426b7..922706ada1 100644
--- a/src/net/http/fs.go
+++ b/src/net/http/fs.go
@@ -30,11 +30,13 @@ import (
// value is a filename on the native file system, not a URL, so it is separated
// by filepath.Separator, which isn't necessarily '/'.
//
-// Note that Dir will allow access to files and directories starting with a
-// period, which could expose sensitive directories like a .git directory or
-// sensitive files like .htpasswd. To exclude files with a leading period,
-// remove the files/directories from the server or create a custom FileSystem
-// implementation.
+// Note that Dir could expose sensitive files and directories. Dir will follow
+// symlinks pointing out of the directory tree, which can be especially dangerous
+// if serving from a directory in which users are able to create arbitrary symlinks.
+// Dir will also allow access to files and directories starting with a period,
+// which could expose sensitive directories like .git or sensitive files like
+// .htpasswd. To exclude files with a leading period, remove the files/directories
+// from the server or create a custom FileSystem implementation.
//
// An empty Dir is treated as ".".
type Dir string
@@ -411,6 +413,7 @@ func checkIfNoneMatch(w ResponseWriter, r *Request) condResult {
}
if buf[0] == ',' {
buf = buf[1:]
+ continue
}
if buf[0] == '*' {
return condFalse
diff --git a/src/net/http/fs_test.go b/src/net/http/fs_test.go
index 435e34be3a..c082ceee71 100644
--- a/src/net/http/fs_test.go
+++ b/src/net/http/fs_test.go
@@ -849,6 +849,15 @@ func TestServeContent(t *testing.T) {
wantStatus: 200,
wantContentType: "text/css; charset=utf-8",
},
+ "if_none_match_malformed": {
+ file: "testdata/style.css",
+ serveETag: `"foo"`,
+ reqHeader: map[string]string{
+ "If-None-Match": `,`,
+ },
+ wantStatus: 200,
+ wantContentType: "text/css; charset=utf-8",
+ },
"range_good": {
file: "testdata/style.css",
serveETag: `"A"`,
diff --git a/src/net/http/httptest/recorder.go b/src/net/http/httptest/recorder.go
index 13697454cb..66e67e78b3 100644
--- a/src/net/http/httptest/recorder.go
+++ b/src/net/http/httptest/recorder.go
@@ -226,9 +226,9 @@ func parseContentLength(cl string) int64 {
if cl == "" {
return -1
}
- n, err := strconv.ParseInt(cl, 10, 64)
+ n, err := strconv.ParseUint(cl, 10, 63)
if err != nil {
return -1
}
- return n
+ return int64(n)
}
diff --git a/src/net/http/httptest/recorder_test.go b/src/net/http/httptest/recorder_test.go
index 0986554aa8..e9534894b6 100644
--- a/src/net/http/httptest/recorder_test.go
+++ b/src/net/http/httptest/recorder_test.go
@@ -310,3 +310,39 @@ func TestRecorder(t *testing.T) {
})
}
}
+
+// issue 39017 - disallow Content-Length values such as "+3"
+func TestParseContentLength(t *testing.T) {
+ tests := []struct {
+ cl string
+ want int64
+ }{
+ {
+ cl: "3",
+ want: 3,
+ },
+ {
+ cl: "+3",
+ want: -1,
+ },
+ {
+ cl: "-3",
+ want: -1,
+ },
+ {
+ // max int64, for safe conversion before returning
+ cl: "9223372036854775807",
+ want: 9223372036854775807,
+ },
+ {
+ cl: "9223372036854775808",
+ want: -1,
+ },
+ }
+
+ for _, tt := range tests {
+ if got := parseContentLength(tt.cl); got != tt.want {
+ t.Errorf("%q:\n\tgot=%d\n\twant=%d", tt.cl, got, tt.want)
+ }
+ }
+}
diff --git a/src/net/http/pprof/pprof.go b/src/net/http/pprof/pprof.go
index 4fd19eb539..81df0448e9 100644
--- a/src/net/http/pprof/pprof.go
+++ b/src/net/http/pprof/pprof.go
@@ -36,15 +36,17 @@
//
// go tool pprof http://localhost:6060/debug/pprof/block
//
-// Or to collect a 5-second execution trace:
-//
-// wget http://localhost:6060/debug/pprof/trace?seconds=5
-//
// Or to look at the holders of contended mutexes, after calling
// runtime.SetMutexProfileFraction in your program:
//
// go tool pprof http://localhost:6060/debug/pprof/mutex
//
+// The package also exports a handler that serves execution trace data
+// for the "go tool trace" command. To collect a 5-second execution trace:
+//
+// wget -O trace.out http://localhost:6060/debug/pprof/trace?seconds=5
+// go tool trace trace.out
+//
// To view all available profiles, open http://localhost:6060/debug/pprof/
// in your browser.
//
diff --git a/src/net/http/request.go b/src/net/http/request.go
index e386f13a37..fe6b60982c 100644
--- a/src/net/http/request.go
+++ b/src/net/http/request.go
@@ -425,6 +425,8 @@ func (r *Request) Cookie(name string) (*Cookie, error) {
// AddCookie does not attach more than one Cookie header field. That
// means all cookies, if any, are written into the same line,
// separated by semicolon.
+// AddCookie only sanitizes c's name and value, and does not sanitize
+// a Cookie header already present in the request.
func (r *Request) AddCookie(c *Cookie) {
s := fmt.Sprintf("%s=%s", sanitizeCookieName(c.Name), sanitizeCookieValue(c.Value))
if c := r.Header.Get("Cookie"); c != "" {
@@ -501,7 +503,7 @@ func valueOrDefault(value, def string) string {
// NOTE: This is not intended to reflect the actual Go version being used.
// It was changed at the time of Go 1.1 release because the former User-Agent
-// had ended up on a blacklist for some intrusion detection systems.
+// had ended up blocked by some intrusion detection systems.
// See https://codereview.appspot.com/7532043.
const defaultUserAgent = "Go-http-client/1.1"
diff --git a/src/net/http/server.go b/src/net/http/server.go
index b613c21f16..a995a50658 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -1698,9 +1698,9 @@ func (c *conn) closeWriteAndWait() {
time.Sleep(rstAvoidanceDelay)
}
-// validNextProto reports whether the proto is not a blacklisted ALPN
-// protocol name. Empty and built-in protocol types are blacklisted
-// and can't be overridden with alternate implementations.
+// validNextProto reports whether the proto is a valid ALPN protocol name.
+// Everything is valid except the empty string and built-in protocol types,
+// so that those can't be overridden with alternate implementations.
func validNextProto(proto string) bool {
switch proto {
case "", "http/1.1", "http/1.0":
diff --git a/src/net/http/transfer.go b/src/net/http/transfer.go
index 6d5ea05c32..50d434b1fb 100644
--- a/src/net/http/transfer.go
+++ b/src/net/http/transfer.go
@@ -335,7 +335,7 @@ func (t *transferWriter) writeBody(w io.Writer) error {
var ncopy int64
// Write body. We "unwrap" the body first if it was wrapped in a
- // nopCloser. This is to ensure that we can take advantage of
+ // nopCloser or readTrackingBody. This is to ensure that we can take advantage of
// OS-level optimizations in the event that the body is an
// *os.File.
if t.Body != nil {
@@ -413,7 +413,10 @@ func (t *transferWriter) unwrapBody() io.Reader {
if reflect.TypeOf(t.Body) == nopCloserType {
return reflect.ValueOf(t.Body).Field(0).Interface().(io.Reader)
}
-
+ if r, ok := t.Body.(*readTrackingBody); ok {
+ r.didRead = true
+ return r.ReadCloser
+ }
return t.Body
}
@@ -1036,11 +1039,11 @@ func parseContentLength(cl string) (int64, error) {
if cl == "" {
return -1, nil
}
- n, err := strconv.ParseInt(cl, 10, 64)
- if err != nil || n < 0 {
+ n, err := strconv.ParseUint(cl, 10, 63)
+ if err != nil {
return 0, badStringError("bad Content-Length", cl)
}
- return n, nil
+ return int64(n), nil
}
@@ -1075,6 +1078,9 @@ func isKnownInMemoryReader(r io.Reader) bool {
if reflect.TypeOf(r) == nopCloserType {
return isKnownInMemoryReader(reflect.ValueOf(r).Field(0).Interface().(io.Reader))
}
+ if r, ok := r.(*readTrackingBody); ok {
+ return isKnownInMemoryReader(r.ReadCloser)
+ }
return false
}
diff --git a/src/net/http/transfer_test.go b/src/net/http/transfer_test.go
index e27d34dd78..185225fa93 100644
--- a/src/net/http/transfer_test.go
+++ b/src/net/http/transfer_test.go
@@ -326,3 +326,39 @@ func TestParseTransferEncoding(t *testing.T) {
}
}
}
+
+// issue 39017 - disallow Content-Length values such as "+3"
+func TestParseContentLength(t *testing.T) {
+ tests := []struct {
+ cl string
+ wantErr error
+ }{
+ {
+ cl: "3",
+ wantErr: nil,
+ },
+ {
+ cl: "+3",
+ wantErr: badStringError("bad Content-Length", "+3"),
+ },
+ {
+ cl: "-3",
+ wantErr: badStringError("bad Content-Length", "-3"),
+ },
+ {
+ // max int64, for safe conversion before returning
+ cl: "9223372036854775807",
+ wantErr: nil,
+ },
+ {
+ cl: "9223372036854775808",
+ wantErr: badStringError("bad Content-Length", "9223372036854775808"),
+ },
+ }
+
+ for _, tt := range tests {
+ if _, gotErr := parseContentLength(tt.cl); !reflect.DeepEqual(gotErr, tt.wantErr) {
+ t.Errorf("%q:\n\tgot=%v\n\twant=%v", tt.cl, gotErr, tt.wantErr)
+ }
+ }
+}
diff --git a/src/net/http/transport.go b/src/net/http/transport.go
index b1705d5439..a41e732d98 100644
--- a/src/net/http/transport.go
+++ b/src/net/http/transport.go
@@ -511,10 +511,18 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
}
}
+ origReq := req
+ req = setupRewindBody(req)
+
if altRT := t.alternateRoundTripper(req); altRT != nil {
if resp, err := altRT.RoundTrip(req); err != ErrSkipAltProtocol {
return resp, err
}
+ var err error
+ req, err = rewindBody(req)
+ if err != nil {
+ return nil, err
+ }
}
if !isHTTP {
req.closeBody()
@@ -565,6 +573,7 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
resp, err = pconn.roundTrip(treq)
}
if err == nil {
+ resp.Request = origReq
return resp, nil
}
@@ -584,18 +593,59 @@ func (t *Transport) roundTrip(req *Request) (*Response, error) {
testHookRoundTripRetried()
// Rewind the body if we're able to.
- if req.GetBody != nil {
- newReq := *req
- var err error
- newReq.Body, err = req.GetBody()
- if err != nil {
- return nil, err
- }
- req = &newReq
+ req, err = rewindBody(req)
+ if err != nil {
+ return nil, err
}
}
}
+var errCannotRewind = errors.New("net/http: cannot rewind body after connection loss")
+
+type readTrackingBody struct {
+ io.ReadCloser
+ didRead bool
+}
+
+func (r *readTrackingBody) Read(data []byte) (int, error) {
+ r.didRead = true
+ return r.ReadCloser.Read(data)
+}
+
+// setupRewindBody returns a new request with a custom body wrapper
+// that can report whether the body needs rewinding.
+// This lets rewindBody avoid an error result when the request
+// does not have GetBody but the body hasn't been read at all yet.
+func setupRewindBody(req *Request) *Request {
+ if req.Body == nil || req.Body == NoBody {
+ return req
+ }
+ newReq := *req
+ newReq.Body = &readTrackingBody{ReadCloser: req.Body}
+ return &newReq
+}
+
+// rewindBody returns a new request with the body rewound.
+// It returns req unmodified if the body does not need rewinding.
+// rewindBody takes care of closing req.Body when appropriate
+// (in all cases except when rewindBody returns req unmodified).
+func rewindBody(req *Request) (rewound *Request, err error) {
+ if req.Body == nil || req.Body == NoBody || !req.Body.(*readTrackingBody).didRead {
+ return req, nil // nothing to rewind
+ }
+ req.closeBody()
+ if req.GetBody == nil {
+ return nil, errCannotRewind
+ }
+ body, err := req.GetBody()
+ if err != nil {
+ return nil, err
+ }
+ newReq := *req
+ newReq.Body = &readTrackingBody{ReadCloser: body}
+ return &newReq, nil
+}
+
// shouldRetryRequest reports whether we should retry sending a failed
// HTTP request on a new connection. The non-nil input error is the
// error from roundTrip.
diff --git a/src/net/http/transport_test.go b/src/net/http/transport_test.go
index f4014d95bb..31a41f5351 100644
--- a/src/net/http/transport_test.go
+++ b/src/net/http/transport_test.go
@@ -3511,7 +3511,8 @@ func TestRetryRequestsOnError(t *testing.T) {
for i := 0; i < 3; i++ {
t0 := time.Now()
- res, err := c.Do(tc.req())
+ req := tc.req()
+ res, err := c.Do(req)
if err != nil {
if time.Since(t0) < MaxWriteWaitBeforeConnReuse/2 {
mu.Lock()
@@ -3522,6 +3523,9 @@ func TestRetryRequestsOnError(t *testing.T) {
t.Skipf("connection likely wasn't recycled within %d, interfering with actual test; skipping", MaxWriteWaitBeforeConnReuse)
}
res.Body.Close()
+ if res.Request != req {
+ t.Errorf("Response.Request != original request; want identical Request")
+ }
}
mu.Lock()
@@ -6196,3 +6200,48 @@ func (timeoutProto) RoundTrip(req *Request) (*Response, error) {
return nil, errors.New("request was not canceled")
}
}
+
+type roundTripFunc func(r *Request) (*Response, error)
+
+func (f roundTripFunc) RoundTrip(r *Request) (*Response, error) { return f(r) }
+
+// Issue 32441: body is not reset after ErrSkipAltProtocol
+func TestIssue32441(t *testing.T) {
+ defer afterTest(t)
+ ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ if n, _ := io.Copy(ioutil.Discard, r.Body); n == 0 {
+ t.Error("body length is zero")
+ }
+ }))
+ defer ts.Close()
+ c := ts.Client()
+ c.Transport.(*Transport).RegisterProtocol("http", roundTripFunc(func(r *Request) (*Response, error) {
+ // Draining body to trigger failure condition on actual request to server.
+ if n, _ := io.Copy(ioutil.Discard, r.Body); n == 0 {
+ t.Error("body length is zero during round trip")
+ }
+ return nil, ErrSkipAltProtocol
+ }))
+ if _, err := c.Post(ts.URL, "application/octet-stream", bytes.NewBufferString("data")); err != nil {
+ t.Error(err)
+ }
+}
+
+// Issue 39017. Ensure that HTTP/1 transports reject Content-Length headers
+// that contain a sign (eg. "+3"), per RFC 2616, Section 14.13.
+func TestTransportRejectsSignInContentLength(t *testing.T) {
+ cst := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
+ w.Header().Set("Content-Length", "+3")
+ w.Write([]byte("abc"))
+ }))
+ defer cst.Close()
+
+ c := cst.Client()
+ res, err := c.Get(cst.URL)
+ if err == nil || res != nil {
+ t.Fatal("Expected a non-nil error and a nil http.Response")
+ }
+ if got, want := err.Error(), `bad Content-Length "+3"`; !strings.Contains(got, want) {
+ t.Fatalf("Error mismatch\nGot: %q\nWanted substring: %q", got, want)
+ }
+}
diff --git a/src/net/interface_plan9.go b/src/net/interface_plan9.go
index 1295017a1b..31bbaca467 100644
--- a/src/net/interface_plan9.go
+++ b/src/net/interface_plan9.go
@@ -68,8 +68,8 @@ func readInterface(i int) (*Interface, error) {
}
ifc.MTU = mtu
- // Not a loopback device
- if device != "/dev/null" {
+ // Not a loopback device ("/dev/null") or packet interface (e.g. "pkt2")
+ if stringsHasPrefix(device, netdir+"/") {
deviceaddrf, err := open(device + "/addr")
if err != nil {
return nil, err
diff --git a/src/net/ipsock_plan9.go b/src/net/ipsock_plan9.go
index eaf3064955..9db01b090d 100644
--- a/src/net/ipsock_plan9.go
+++ b/src/net/ipsock_plan9.go
@@ -199,7 +199,11 @@ func dialPlan9Blocking(ctx context.Context, net string, laddr, raddr Addr) (fd *
if err != nil {
return nil, err
}
- _, err = f.WriteString("connect " + dest)
+ if la := plan9LocalAddr(laddr); la == "" {
+ _, err = f.WriteString("connect " + dest)
+ } else {
+ _, err = f.WriteString("connect " + dest + " " + la)
+ }
if err != nil {
f.Close()
return nil, err
@@ -303,3 +307,29 @@ func toLocal(a Addr, net string) Addr {
}
return a
}
+
+// plan9LocalAddr returns a Plan 9 local address string.
+// See setladdrport at https://9p.io/sources/plan9/sys/src/9/ip/devip.c.
+func plan9LocalAddr(addr Addr) string {
+ var ip IP
+ port := 0
+ switch a := addr.(type) {
+ case *TCPAddr:
+ if a != nil {
+ ip = a.IP
+ port = a.Port
+ }
+ case *UDPAddr:
+ if a != nil {
+ ip = a.IP
+ port = a.Port
+ }
+ }
+ if len(ip) == 0 || ip.IsUnspecified() {
+ if port == 0 {
+ return ""
+ }
+ return itoa(port)
+ }
+ return ip.String() + "!" + itoa(port)
+}
diff --git a/src/net/net.go b/src/net/net.go
index 82b71565aa..2e61a7c02e 100644
--- a/src/net/net.go
+++ b/src/net/net.go
@@ -111,13 +111,13 @@ type Addr interface {
// Multiple goroutines may invoke methods on a Conn simultaneously.
type Conn interface {
// Read reads data from the connection.
- // Read can be made to time out and return an Error with Timeout() == true
- // after a fixed time limit; see SetDeadline and SetReadDeadline.
+ // Read can be made to time out and return an error after a fixed
+ // time limit; see SetDeadline and SetReadDeadline.
Read(b []byte) (n int, err error)
// Write writes data to the connection.
- // Write can be made to time out and return an Error with Timeout() == true
- // after a fixed time limit; see SetDeadline and SetWriteDeadline.
+ // Write can be made to time out and return an error after a fixed
+ // time limit; see SetDeadline and SetWriteDeadline.
Write(b []byte) (n int, err error)
// Close closes the connection.
@@ -313,15 +313,13 @@ type PacketConn interface {
// It returns the number of bytes read (0 <= n <= len(p))
// and any error encountered. Callers should always process
// the n > 0 bytes returned before considering the error err.
- // ReadFrom can be made to time out and return
- // an Error with Timeout() == true after a fixed time limit;
- // see SetDeadline and SetReadDeadline.
+ // ReadFrom can be made to time out and return an error after a
+ // fixed time limit; see SetDeadline and SetReadDeadline.
ReadFrom(p []byte) (n int, addr Addr, err error)
// WriteTo writes a packet with payload p to addr.
- // WriteTo can be made to time out and return
- // an Error with Timeout() == true after a fixed time limit;
- // see SetDeadline and SetWriteDeadline.
+ // WriteTo can be made to time out and return an Error after a
+ // fixed time limit; see SetDeadline and SetWriteDeadline.
// On packet-oriented connections, write timeouts are rare.
WriteTo(p []byte, addr Addr) (n int, err error)
@@ -337,11 +335,17 @@ type PacketConn interface {
// SetReadDeadline and SetWriteDeadline.
//
// A deadline is an absolute time after which I/O operations
- // fail with a timeout (see type Error) instead of
- // blocking. The deadline applies to all future and pending
- // I/O, not just the immediately following call to ReadFrom or
- // WriteTo. After a deadline has been exceeded, the connection
- // can be refreshed by setting a deadline in the future.
+ // fail instead of blocking. The deadline applies to all future
+ // and pending I/O, not just the immediately following call to
+ // Read or Write. After a deadline has been exceeded, the
+ // connection can be refreshed by setting a deadline in the future.
+ //
+ // If the deadline is exceeded a call to Read or Write or to other
+ // I/O methods will return an error that wraps os.ErrDeadlineExceeded.
+ // This can be tested using errors.Is(err, os.ErrDeadlineExceeded).
+ // The error's Timeout method will return true, but note that there
+ // are other possible errors for which the Timeout method will
+ // return true even if the deadline has not been exceeded.
//
// An idle timeout can be implemented by repeatedly extending
// the deadline after successful ReadFrom or WriteTo calls.
diff --git a/src/net/rpc/client.go b/src/net/rpc/client.go
index cad2d45e7f..25f2a004e4 100644
--- a/src/net/rpc/client.go
+++ b/src/net/rpc/client.go
@@ -31,7 +31,7 @@ type Call struct {
Args interface{} // The argument to the function (*struct).
Reply interface{} // The reply from the function (*struct).
Error error // After completion, the error status.
- Done chan *Call // Strobes when call is complete.
+ Done chan *Call // Receives *Call when Go is complete.
}
// Client represents an RPC Client.
diff --git a/src/net/sockopt_aix.go b/src/net/sockopt_aix.go
index b49c4d5c7c..7729a4470b 100644
--- a/src/net/sockopt_aix.go
+++ b/src/net/sockopt_aix.go
@@ -16,8 +16,11 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_bsd.go b/src/net/sockopt_bsd.go
index 4ecc8cb1cf..8fd1e882c6 100644
--- a/src/net/sockopt_bsd.go
+++ b/src/net/sockopt_bsd.go
@@ -31,8 +31,11 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_linux.go b/src/net/sockopt_linux.go
index 0f70b12407..3d544299ac 100644
--- a/src/net/sockopt_linux.go
+++ b/src/net/sockopt_linux.go
@@ -16,8 +16,11 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_solaris.go b/src/net/sockopt_solaris.go
index 0f70b12407..3d544299ac 100644
--- a/src/net/sockopt_solaris.go
+++ b/src/net/sockopt_solaris.go
@@ -16,8 +16,11 @@ func setDefaultSockopts(s, family, sotype int, ipv6only bool) error {
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
+ return nil
}
func setDefaultListenerSockopts(s int) error {
diff --git a/src/net/sockopt_windows.go b/src/net/sockopt_windows.go
index 8017426521..8afaf34514 100644
--- a/src/net/sockopt_windows.go
+++ b/src/net/sockopt_windows.go
@@ -16,8 +16,10 @@ func setDefaultSockopts(s syscall.Handle, family, sotype int, ipv6only bool) err
// never admit this option.
syscall.SetsockoptInt(s, syscall.IPPROTO_IPV6, syscall.IPV6_V6ONLY, boolint(ipv6only))
}
- // Allow broadcast.
- syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1)
+ if (sotype == syscall.SOCK_DGRAM || sotype == syscall.SOCK_RAW) && family != syscall.AF_UNIX && family != syscall.AF_INET6 {
+ // Allow broadcast.
+ return os.NewSyscallError("setsockopt", syscall.SetsockoptInt(s, syscall.SOL_SOCKET, syscall.SO_BROADCAST, 1))
+ }
return nil
}
diff --git a/src/os/exec_unix.go b/src/os/exec_unix.go
index 6e4ffe82d2..7759a2d2ea 100644
--- a/src/os/exec_unix.go
+++ b/src/os/exec_unix.go
@@ -33,9 +33,18 @@ func (p *Process) wait() (ps *ProcessState, err error) {
p.sigMu.Unlock()
}
- var status syscall.WaitStatus
- var rusage syscall.Rusage
- pid1, e := syscall.Wait4(p.Pid, &status, 0, &rusage)
+ var (
+ status syscall.WaitStatus
+ rusage syscall.Rusage
+ pid1 int
+ e error
+ )
+ for {
+ pid1, e = syscall.Wait4(p.Pid, &status, 0, &rusage)
+ if e != syscall.EINTR {
+ break
+ }
+ }
if e != nil {
return nil, NewSyscallError("wait", e)
}
diff --git a/src/os/file.go b/src/os/file.go
index 93ba4d78ad..a2b71cb61a 100644
--- a/src/os/file.go
+++ b/src/os/file.go
@@ -384,7 +384,7 @@ func TempDir() string {
// within this one and use that.
//
// On Unix systems, it returns $XDG_CACHE_HOME as specified by
-// https://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html if
+// https://specifications.freedesktop.org/basedir-spec/basedir-spec-latest.html if
// non-empty, else $HOME/.cache.
// On Darwin, it returns $HOME/Library/Caches.
// On Windows, it returns %LocalAppData%.
diff --git a/src/os/file_plan9.go b/src/os/file_plan9.go
index ac68cf7fed..eb158905ab 100644
--- a/src/os/file_plan9.go
+++ b/src/os/file_plan9.go
@@ -233,10 +233,10 @@ func (f *File) Sync() error {
var buf [syscall.STATFIXLEN]byte
n, err := d.Marshal(buf[:])
if err != nil {
- return NewSyscallError("fsync", err)
+ return &PathError{"sync", f.name, err}
}
if err = syscall.Fwstat(f.fd, buf[:n]); err != nil {
- return NewSyscallError("fsync", err)
+ return &PathError{"sync", f.name, err}
}
return nil
}
diff --git a/src/os/file_unix.go b/src/os/file_unix.go
index b93e2bd56a..f2c00ae0cb 100644
--- a/src/os/file_unix.go
+++ b/src/os/file_unix.go
@@ -202,10 +202,8 @@ func openFileNolog(name string, flag int, perm FileMode) (*File, error) {
break
}
- // On OS X, sigaction(2) doesn't guarantee that SA_RESTART will cause
- // open(2) to be restarted for regular files. This is easy to reproduce on
- // fuse file systems (see https://golang.org/issue/11180).
- if runtime.GOOS == "darwin" && e == syscall.EINTR {
+ // We have to check EINTR here, per issues 11180 and 39237.
+ if e == syscall.EINTR {
continue
}
diff --git a/src/os/file_windows.go b/src/os/file_windows.go
index 0d8c0fd20d..cc695fd94c 100644
--- a/src/os/file_windows.go
+++ b/src/os/file_windows.go
@@ -330,8 +330,18 @@ func Symlink(oldname, newname string) error {
// need the exact location of the oldname when it's relative to determine if it's a directory
destpath := oldname
- if !isAbs(oldname) {
- destpath = dirname(newname) + `\` + oldname
+ if v := volumeName(oldname); v == "" {
+ if len(oldname) > 0 && IsPathSeparator(oldname[0]) {
+ // oldname is relative to the volume containing newname.
+ if v = volumeName(newname); v != "" {
+ // Prepend the volume explicitly, because it may be different from the
+ // volume of the current working directory.
+ destpath = v + oldname
+ }
+ } else {
+ // oldname is relative to newname.
+ destpath = dirname(newname) + `\` + oldname
+ }
}
fi, err := Stat(destpath)
diff --git a/src/os/os_test.go b/src/os/os_test.go
index f86428b7b9..e8c64510f5 100644
--- a/src/os/os_test.go
+++ b/src/os/os_test.go
@@ -2539,3 +2539,34 @@ func isDeadlineExceeded(err error) bool {
}
return true
}
+
+// Test that opening a file does not change its permissions. Issue 38225.
+func TestOpenFileKeepsPermissions(t *testing.T) {
+ t.Parallel()
+ dir := t.TempDir()
+ name := filepath.Join(dir, "x")
+ f, err := Create(name)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ t.Error(err)
+ }
+ f, err = OpenFile(name, O_WRONLY|O_CREATE|O_TRUNC, 0)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if fi, err := f.Stat(); err != nil {
+ t.Error(err)
+ } else if fi.Mode()&0222 == 0 {
+ t.Errorf("f.Stat.Mode after OpenFile is %v, should be writable", fi.Mode())
+ }
+ if err := f.Close(); err != nil {
+ t.Error(err)
+ }
+ if fi, err := Stat(name); err != nil {
+ t.Error(err)
+ } else if fi.Mode()&0222 == 0 {
+ t.Errorf("Stat after OpenFile is %v, should be writable", fi.Mode())
+ }
+}
diff --git a/src/os/os_windows_test.go b/src/os/os_windows_test.go
index 8c14103143..f03ec750d0 100644
--- a/src/os/os_windows_test.go
+++ b/src/os/os_windows_test.go
@@ -965,9 +965,10 @@ func TestWindowsDevNullFile(t *testing.T) {
// works on Windows when developer mode is active.
// This is supported starting Windows 10 (1703, v10.0.14972).
func TestSymlinkCreation(t *testing.T) {
- if !isWindowsDeveloperModeActive() {
+ if !testenv.HasSymlink() && !isWindowsDeveloperModeActive() {
t.Skip("Windows developer mode is not active")
}
+ t.Parallel()
temp, err := ioutil.TempDir("", "TestSymlinkCreation")
if err != nil {
@@ -1005,6 +1006,122 @@ func isWindowsDeveloperModeActive() bool {
return val != 0
}
+// TestRootRelativeDirSymlink verifies that symlinks to paths relative to the
+// drive root (beginning with "\" but no volume name) are created with the
+// correct symlink type.
+// (See https://golang.org/issue/39183#issuecomment-632175728.)
+func TestRootRelativeDirSymlink(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+ t.Parallel()
+
+ temp := t.TempDir()
+ dir := filepath.Join(temp, "dir")
+ if err := os.Mkdir(dir, 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ volumeRelDir := strings.TrimPrefix(dir, filepath.VolumeName(dir)) // leaves leading backslash
+
+ link := filepath.Join(temp, "link")
+ err := os.Symlink(volumeRelDir, link)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Symlink(%#q, %#q)", volumeRelDir, link)
+
+ f, err := os.Open(link)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer f.Close()
+ if fi, err := f.Stat(); err != nil {
+ t.Fatal(err)
+ } else if !fi.IsDir() {
+ t.Errorf("Open(%#q).Stat().IsDir() = false; want true", f.Name())
+ }
+}
+
+// TestWorkingDirectoryRelativeSymlink verifies that symlinks to paths relative
+// to the current working directory for the drive, such as "C:File.txt", are
+// correctly converted to absolute links of the correct symlink type (per
+// https://docs.microsoft.com/en-us/windows/win32/fileio/creating-symbolic-links).
+func TestWorkingDirectoryRelativeSymlink(t *testing.T) {
+ testenv.MustHaveSymlink(t)
+
+ // Construct a directory to be symlinked.
+ temp := t.TempDir()
+ if v := filepath.VolumeName(temp); len(v) < 2 || v[1] != ':' {
+ t.Skipf("Can't test relative symlinks: t.TempDir() (%#q) does not begin with a drive letter.", temp)
+ }
+
+ absDir := filepath.Join(temp, `dir\sub`)
+ if err := os.MkdirAll(absDir, 0755); err != nil {
+ t.Fatal(err)
+ }
+
+ // Change to the temporary directory and construct a
+ // working-directory-relative symlink.
+ oldwd, err := os.Getwd()
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer func() {
+ if err := os.Chdir(oldwd); err != nil {
+ t.Fatal(err)
+ }
+ }()
+ if err := os.Chdir(temp); err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Chdir(%#q)", temp)
+
+ wdRelDir := filepath.VolumeName(temp) + `dir\sub` // no backslash after volume.
+ absLink := filepath.Join(temp, "link")
+ err = os.Symlink(wdRelDir, absLink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Symlink(%#q, %#q)", wdRelDir, absLink)
+
+ // Now change back to the original working directory and verify that the
+ // symlink still refers to its original path and is correctly marked as a
+ // directory.
+ if err := os.Chdir(oldwd); err != nil {
+ t.Fatal(err)
+ }
+ t.Logf("Chdir(%#q)", oldwd)
+
+ resolved, err := os.Readlink(absLink)
+ if err != nil {
+ t.Errorf("Readlink(%#q): %v", absLink, err)
+ } else if resolved != absDir {
+ t.Errorf("Readlink(%#q) = %#q; want %#q", absLink, resolved, absDir)
+ }
+
+ linkFile, err := os.Open(absLink)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer linkFile.Close()
+
+ linkInfo, err := linkFile.Stat()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !linkInfo.IsDir() {
+ t.Errorf("Open(%#q).Stat().IsDir() = false; want true", absLink)
+ }
+
+ absInfo, err := os.Stat(absDir)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !os.SameFile(absInfo, linkInfo) {
+ t.Errorf("SameFile(Stat(%#q), Open(%#q).Stat()) = false; want true", absDir, absLink)
+ }
+}
+
// TestStatOfInvalidName is regression test for issue #24999.
func TestStatOfInvalidName(t *testing.T) {
_, err := os.Stat("*.go")
diff --git a/src/os/readfrom_linux_test.go b/src/os/readfrom_linux_test.go
index cecaed5214..b6f5cb7034 100644
--- a/src/os/readfrom_linux_test.go
+++ b/src/os/readfrom_linux_test.go
@@ -249,14 +249,15 @@ func newCopyFileRangeTest(t *testing.T, size int64) (dst, src *File, data []byte
t.Helper()
hook = hookCopyFileRange(t)
+ tmp := t.TempDir()
- src, err := Create(filepath.Join(t.TempDir(), "src"))
+ src, err := Create(filepath.Join(tmp, "src"))
if err != nil {
t.Fatal(err)
}
t.Cleanup(func() { src.Close() })
- dst, err = Create(filepath.Join(t.TempDir(), "dst"))
+ dst, err = Create(filepath.Join(tmp, "dst"))
if err != nil {
t.Fatal(err)
}
diff --git a/src/os/removeall_at.go b/src/os/removeall_at.go
index e619851f9c..37bf1b8f2f 100644
--- a/src/os/removeall_at.go
+++ b/src/os/removeall_at.go
@@ -9,7 +9,6 @@ package os
import (
"internal/syscall/unix"
"io"
- "runtime"
"syscall"
)
@@ -178,7 +177,7 @@ func openFdAt(dirfd int, name string) (*File, error) {
}
// See comment in openFileNolog.
- if runtime.GOOS == "darwin" && e == syscall.EINTR {
+ if e == syscall.EINTR {
continue
}
diff --git a/src/os/signal/internal/pty/pty.go b/src/os/signal/internal/pty/pty.go
index fb3ee1ea7a..f8813ce6be 100644
--- a/src/os/signal/internal/pty/pty.go
+++ b/src/os/signal/internal/pty/pty.go
@@ -40,8 +40,8 @@ func (e *PtyError) Error() string {
func (e *PtyError) Unwrap() error { return e.Errno }
-// Open returns a master pty and the name of the linked slave tty.
-func Open() (master *os.File, slave string, err error) {
+// Open returns a control pty and the name of the linked process tty.
+func Open() (pty *os.File, processTTY string, err error) {
m, err := C.posix_openpt(C.O_RDWR)
if err != nil {
return nil, "", ptyError("posix_openpt", err)
@@ -54,6 +54,6 @@ func Open() (master *os.File, slave string, err error) {
C.close(m)
return nil, "", ptyError("unlockpt", err)
}
- slave = C.GoString(C.ptsname(m))
- return os.NewFile(uintptr(m), "pty-master"), slave, nil
+ processTTY = C.GoString(C.ptsname(m))
+ return os.NewFile(uintptr(m), "pty"), processTTY, nil
}
diff --git a/src/os/signal/signal_cgo_test.go b/src/os/signal/signal_cgo_test.go
index 849a96ec0e..a117221400 100644
--- a/src/os/signal/signal_cgo_test.go
+++ b/src/os/signal/signal_cgo_test.go
@@ -19,7 +19,7 @@ import (
"io"
"os"
"os/exec"
- "os/signal/internal/pty"
+ ptypkg "os/signal/internal/pty"
"strconv"
"strings"
"sync"
@@ -71,20 +71,20 @@ func TestTerminalSignal(t *testing.T) {
// The test only fails when using a "slow device," in this
// case a pseudo-terminal.
- master, sname, err := pty.Open()
+ pty, procTTYName, err := ptypkg.Open()
if err != nil {
- ptyErr := err.(*pty.PtyError)
+ ptyErr := err.(*ptypkg.PtyError)
if ptyErr.FuncName == "posix_openpt" && ptyErr.Errno == syscall.EACCES {
t.Skip("posix_openpt failed with EACCES, assuming chroot and skipping")
}
t.Fatal(err)
}
- defer master.Close()
- slave, err := os.OpenFile(sname, os.O_RDWR, 0)
+ defer pty.Close()
+ procTTY, err := os.OpenFile(procTTYName, os.O_RDWR, 0)
if err != nil {
t.Fatal(err)
}
- defer slave.Close()
+ defer procTTY.Close()
// Start an interactive shell.
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
@@ -92,9 +92,9 @@ func TestTerminalSignal(t *testing.T) {
cmd := exec.CommandContext(ctx, bash, "--norc", "--noprofile", "-i")
// Clear HISTFILE so that we don't read or clobber the user's bash history.
cmd.Env = append(os.Environ(), "HISTFILE=")
- cmd.Stdin = slave
- cmd.Stdout = slave
- cmd.Stderr = slave
+ cmd.Stdin = procTTY
+ cmd.Stdout = procTTY
+ cmd.Stderr = procTTY
cmd.SysProcAttr = &syscall.SysProcAttr{
Setsid: true,
Setctty: true,
@@ -105,21 +105,21 @@ func TestTerminalSignal(t *testing.T) {
t.Fatal(err)
}
- if err := slave.Close(); err != nil {
- t.Errorf("closing slave: %v", err)
+ if err := procTTY.Close(); err != nil {
+ t.Errorf("closing procTTY: %v", err)
}
progReady := make(chan bool)
sawPrompt := make(chan bool, 10)
const prompt = "prompt> "
- // Read data from master in the background.
+ // Read data from pty in the background.
var wg sync.WaitGroup
wg.Add(1)
defer wg.Wait()
go func() {
defer wg.Done()
- input := bufio.NewReader(master)
+ input := bufio.NewReader(pty)
var line, handled []byte
for {
b, err := input.ReadByte()
@@ -130,11 +130,11 @@ func TestTerminalSignal(t *testing.T) {
if perr, ok := err.(*os.PathError); ok {
err = perr.Err
}
- // EOF means master is closed.
+ // EOF means pty is closed.
// EIO means child process is done.
- // "file already closed" means deferred close of master has happened.
+ // "file already closed" means deferred close of pty has happened.
if err != io.EOF && err != syscall.EIO && !strings.Contains(err.Error(), "file already closed") {
- t.Logf("error reading from master: %v", err)
+ t.Logf("error reading from pty: %v", err)
}
return
}
@@ -161,7 +161,7 @@ func TestTerminalSignal(t *testing.T) {
}()
// Set the bash prompt so that we can see it.
- if _, err := master.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
+ if _, err := pty.Write([]byte("PS1='" + prompt + "'\n")); err != nil {
t.Fatalf("setting prompt: %v", err)
}
select {
@@ -172,7 +172,7 @@ func TestTerminalSignal(t *testing.T) {
// Start a small program that reads from stdin
// (namely the code at the top of this function).
- if _, err := master.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
+ if _, err := pty.Write([]byte("GO_TEST_TERMINAL_SIGNALS=1 " + os.Args[0] + " -test.run=TestTerminalSignal\n")); err != nil {
t.Fatal(err)
}
@@ -190,7 +190,7 @@ func TestTerminalSignal(t *testing.T) {
time.Sleep(pause)
// Send a ^Z to stop the program.
- if _, err := master.Write([]byte{26}); err != nil {
+ if _, err := pty.Write([]byte{26}); err != nil {
t.Fatalf("writing ^Z to pty: %v", err)
}
@@ -202,7 +202,7 @@ func TestTerminalSignal(t *testing.T) {
}
// Restart the stopped program.
- if _, err := master.Write([]byte("fg\n")); err != nil {
+ if _, err := pty.Write([]byte("fg\n")); err != nil {
t.Fatalf("writing %q to pty: %v", "fg", err)
}
@@ -217,7 +217,7 @@ func TestTerminalSignal(t *testing.T) {
// Write some data for the program to read,
// which should cause it to exit.
- if _, err := master.Write([]byte{'\n'}); err != nil {
+ if _, err := pty.Write([]byte{'\n'}); err != nil {
t.Fatalf("writing %q to pty: %v", "\n", err)
}
@@ -229,7 +229,7 @@ func TestTerminalSignal(t *testing.T) {
}
// Exit the shell with the program's exit status.
- if _, err := master.Write([]byte("exit $?\n")); err != nil {
+ if _, err := pty.Write([]byte("exit $?\n")); err != nil {
t.Fatalf("writing %q to pty: %v", "exit", err)
}
diff --git a/src/os/wait_wait6.go b/src/os/wait_wait6.go
index 45bf649015..5420b2db73 100644
--- a/src/os/wait_wait6.go
+++ b/src/os/wait_wait6.go
@@ -18,15 +18,20 @@ const _P_PID = 0
// It does not actually call p.Wait.
func (p *Process) blockUntilWaitable() (bool, error) {
var errno syscall.Errno
- // The arguments on 32-bit FreeBSD look like the following:
- // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
- // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
- if runtime.GOARCH == "386" {
- _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
- } else if runtime.GOARCH == "arm" {
- _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
- } else {
- _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ for {
+ // The arguments on 32-bit FreeBSD look like the following:
+ // - freebsd32_wait6_args{ idtype, id1, id2, status, options, wrusage, info } or
+ // - freebsd32_wait6_args{ idtype, pad, id1, id2, status, options, wrusage, info } when PAD64_REQUIRED=1 on ARM, MIPS or PowerPC
+ if runtime.GOARCH == "386" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0, 0)
+ } else if runtime.GOARCH == "arm" {
+ _, _, errno = syscall.Syscall9(syscall.SYS_WAIT6, _P_PID, 0, uintptr(p.Pid), 0, 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0, 0)
+ } else {
+ _, _, errno = syscall.Syscall6(syscall.SYS_WAIT6, _P_PID, uintptr(p.Pid), 0, syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ }
+ if errno != syscall.EINTR {
+ break
+ }
}
runtime.KeepAlive(p)
if errno != 0 {
diff --git a/src/os/wait_waitid.go b/src/os/wait_waitid.go
index 6c904e54db..9c56eb2d41 100644
--- a/src/os/wait_waitid.go
+++ b/src/os/wait_waitid.go
@@ -27,7 +27,13 @@ func (p *Process) blockUntilWaitable() (bool, error) {
// We don't care about the values it returns.
var siginfo [16]uint64
psig := &siginfo[0]
- _, _, e := syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ var e syscall.Errno
+ for {
+ _, _, e = syscall.Syscall6(syscall.SYS_WAITID, _P_PID, uintptr(p.Pid), uintptr(unsafe.Pointer(psig)), syscall.WEXITED|syscall.WNOWAIT, 0, 0)
+ if e != syscall.EINTR {
+ break
+ }
+ }
runtime.KeepAlive(p)
if e != 0 {
// waitid has been available since Linux 2.6.9, but
diff --git a/src/path/filepath/match.go b/src/path/filepath/match.go
index 46badb5e84..20a334805b 100644
--- a/src/path/filepath/match.go
+++ b/src/path/filepath/match.go
@@ -310,14 +310,14 @@ func glob(dir, pattern string, matches []string) (m []string, e error) {
m = matches
fi, err := os.Stat(dir)
if err != nil {
- return
+ return // ignore I/O error
}
if !fi.IsDir() {
- return
+ return // ignore I/O error
}
d, err := os.Open(dir)
if err != nil {
- return
+ return // ignore I/O error
}
defer d.Close()
diff --git a/src/race.bat b/src/race.bat
index d26f3180a3..8f0355612c 100644
--- a/src/race.bat
+++ b/src/race.bat
@@ -1,51 +1,51 @@
-:: Copyright 2013 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.
-
-:: race.bash tests the standard library under the race detector.
-:: https://golang.org/doc/articles/race_detector.html
-
-@echo off
-
-setlocal
-
-if exist make.bat goto ok
-echo race.bat must be run from go\src
-:: cannot exit: would kill parent command interpreter
-goto end
-:ok
-
-set GOROOT=%CD%\..
-call make.bat --dist-tool >NUL
-if errorlevel 1 goto fail
-.\cmd\dist\dist.exe env -w -p >env.bat
-if errorlevel 1 goto fail
-call env.bat
-del env.bat
-
-if %GOHOSTARCH% == amd64 goto continue
-echo Race detector is only supported on windows/amd64.
-goto fail
-
-:continue
-call make.bat --no-banner --no-local
-if %GOBUILDFAIL%==1 goto end
-echo # go install -race std
-go install -race std
-if errorlevel 1 goto fail
-
-go tool dist test -race
-
-if errorlevel 1 goto fail
-goto succ
-
-:fail
-set GOBUILDFAIL=1
-echo Fail.
-goto end
-
-:succ
-echo All tests passed.
-
-:end
-if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
+:: Copyright 2013 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.
+
+:: race.bash tests the standard library under the race detector.
+:: https://golang.org/doc/articles/race_detector.html
+
+@echo off
+
+setlocal
+
+if exist make.bat goto ok
+echo race.bat must be run from go\src
+:: cannot exit: would kill parent command interpreter
+goto end
+:ok
+
+set GOROOT=%CD%\..
+call make.bat --dist-tool >NUL
+if errorlevel 1 goto fail
+.\cmd\dist\dist.exe env -w -p >env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+
+if %GOHOSTARCH% == amd64 goto continue
+echo Race detector is only supported on windows/amd64.
+goto fail
+
+:continue
+call make.bat --no-banner --no-local
+if %GOBUILDFAIL%==1 goto end
+echo # go install -race std
+go install -race std
+if errorlevel 1 goto fail
+
+go tool dist test -race
+
+if errorlevel 1 goto fail
+goto succ
+
+:fail
+set GOBUILDFAIL=1
+echo Fail.
+goto end
+
+:succ
+echo All tests passed.
+
+:end
+if x%GOBUILDEXIT%==x1 exit %GOBUILDFAIL%
diff --git a/src/reflect/all_test.go b/src/reflect/all_test.go
index e87d1d27cd..63f6a92157 100644
--- a/src/reflect/all_test.go
+++ b/src/reflect/all_test.go
@@ -824,6 +824,11 @@ var loop1, loop2 Loop
var loopy1, loopy2 Loopy
var cycleMap1, cycleMap2, cycleMap3 map[string]interface{}
+type structWithSelfPtr struct {
+ p *structWithSelfPtr
+ s string
+}
+
func init() {
loop1 = &loop2
loop2 = &loop1
@@ -880,6 +885,7 @@ var deepEqualTests = []DeepEqualTest{
{[]float64{math.NaN()}, self{}, true},
{map[float64]float64{math.NaN(): 1}, map[float64]float64{1: 2}, false},
{map[float64]float64{math.NaN(): 1}, self{}, true},
+ {&structWithSelfPtr{p: &structWithSelfPtr{s: "a"}}, &structWithSelfPtr{p: &structWithSelfPtr{s: "b"}}, false},
// Nil vs empty: not the same.
{[]int{}, []int(nil), false},
diff --git a/src/reflect/deepequal.go b/src/reflect/deepequal.go
index f2d46165b5..8a2bf8b09e 100644
--- a/src/reflect/deepequal.go
+++ b/src/reflect/deepequal.go
@@ -45,8 +45,20 @@ func deepValueEqual(v1, v2 Value, visited map[visit]bool, depth int) bool {
}
if hard(v1, v2) {
- addr1 := v1.ptr
- addr2 := v2.ptr
+ // For a Ptr or Map value, we need to check flagIndir,
+ // which we do by calling the pointer method.
+ // For Slice or Interface, flagIndir is always set,
+ // and using v.ptr suffices.
+ ptrval := func(v Value) unsafe.Pointer {
+ switch v.Kind() {
+ case Ptr, Map:
+ return v.pointer()
+ default:
+ return v.ptr
+ }
+ }
+ addr1 := ptrval(v1)
+ addr2 := ptrval(v2)
if uintptr(addr1) > uintptr(addr2) {
// Canonicalize order to reduce number of entries in visited.
// Assumes non-moving garbage collector.
diff --git a/src/reflect/type.go b/src/reflect/type.go
index ec26bef091..38b1283d42 100644
--- a/src/reflect/type.go
+++ b/src/reflect/type.go
@@ -3068,6 +3068,7 @@ func ifaceIndir(t *rtype) bool {
return t.kind&kindDirectIface == 0
}
+// Note: this type must agree with runtime.bitvector.
type bitVector struct {
n uint32 // number of bits
data []byte
diff --git a/src/reflect/value.go b/src/reflect/value.go
index 8ce495a33b..c6f24a5609 100644
--- a/src/reflect/value.go
+++ b/src/reflect/value.go
@@ -589,6 +589,13 @@ func callReflect(ctxt *makeFuncImpl, frame unsafe.Pointer, retValid *bool) {
// Convert v to type typ if v is assignable to a variable
// of type t in the language spec.
// See issue 28761.
+ if typ.Kind() == Interface {
+ // We must clear the destination before calling assignTo,
+ // in case assignTo writes (with memory barriers) to the
+ // target location used as scratch space. See issue 39541.
+ *(*uintptr)(addr) = 0
+ *(*uintptr)(add(addr, ptrSize, "typ.size == 2*ptrSize")) = 0
+ }
v = v.assignTo("reflect.MakeFunc", typ, addr)
// We are writing to stack. No write barrier.
@@ -2381,6 +2388,7 @@ func NewAt(typ Type, p unsafe.Pointer) Value {
// assignTo returns a value v that can be assigned directly to typ.
// It panics if v is not assignable to typ.
// For a conversion to an interface type, target is a suggested scratch space to use.
+// target must be initialized memory (or nil).
func (v Value) assignTo(context string, dst *rtype, target unsafe.Pointer) Value {
if v.flag&flagMethod != 0 {
v = makeMethodValue(context, v)
diff --git a/src/regexp/syntax/compile.go b/src/regexp/syntax/compile.go
index 1d8ab87a6d..7524d628fe 100644
--- a/src/regexp/syntax/compile.go
+++ b/src/regexp/syntax/compile.go
@@ -12,57 +12,47 @@ import "unicode"
// See https://swtch.com/~rsc/regexp/regexp1.html for inspiration.
//
// These aren't really pointers: they're integers, so we can reinterpret them
-// this way without using package unsafe. A value l denotes
-// p.inst[l>>1].Out (l&1==0) or .Arg (l&1==1).
-// l == 0 denotes the empty list, okay because we start every program
+// this way without using package unsafe. A value l.head denotes
+// p.inst[l.head>>1].Out (l.head&1==0) or .Arg (l.head&1==1).
+// head == 0 denotes the empty list, okay because we start every program
// with a fail instruction, so we'll never want to point at its output link.
-type patchList uint32
+type patchList struct {
+ head, tail uint32
+}
-func (l patchList) next(p *Prog) patchList {
- i := &p.Inst[l>>1]
- if l&1 == 0 {
- return patchList(i.Out)
- }
- return patchList(i.Arg)
+func makePatchList(n uint32) patchList {
+ return patchList{n, n}
}
func (l patchList) patch(p *Prog, val uint32) {
- for l != 0 {
- i := &p.Inst[l>>1]
- if l&1 == 0 {
- l = patchList(i.Out)
+ head := l.head
+ for head != 0 {
+ i := &p.Inst[head>>1]
+ if head&1 == 0 {
+ head = i.Out
i.Out = val
} else {
- l = patchList(i.Arg)
+ head = i.Arg
i.Arg = val
}
}
}
func (l1 patchList) append(p *Prog, l2 patchList) patchList {
- if l1 == 0 {
+ if l1.head == 0 {
return l2
}
- if l2 == 0 {
+ if l2.head == 0 {
return l1
}
- last := l1
- for {
- next := last.next(p)
- if next == 0 {
- break
- }
- last = next
- }
-
- i := &p.Inst[last>>1]
- if last&1 == 0 {
- i.Out = uint32(l2)
+ i := &p.Inst[l1.tail>>1]
+ if l1.tail&1 == 0 {
+ i.Out = l2.head
} else {
- i.Arg = uint32(l2)
+ i.Arg = l2.head
}
- return l1
+ return patchList{l1.head, l2.tail}
}
// A frag represents a compiled program fragment.
@@ -176,7 +166,7 @@ func (c *compiler) inst(op InstOp) frag {
func (c *compiler) nop() frag {
f := c.inst(InstNop)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
return f
}
@@ -186,7 +176,7 @@ func (c *compiler) fail() frag {
func (c *compiler) cap(arg uint32) frag {
f := c.inst(InstCapture)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
c.p.Inst[f.i].Arg = arg
if c.p.NumCap < int(arg)+1 {
@@ -229,10 +219,10 @@ func (c *compiler) quest(f1 frag, nongreedy bool) frag {
i := &c.p.Inst[f.i]
if nongreedy {
i.Arg = f1.i
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
} else {
i.Out = f1.i
- f.out = patchList(f.i<<1 | 1)
+ f.out = makePatchList(f.i<<1 | 1)
}
f.out = f.out.append(c.p, f1.out)
return f
@@ -243,10 +233,10 @@ func (c *compiler) star(f1 frag, nongreedy bool) frag {
i := &c.p.Inst[f.i]
if nongreedy {
i.Arg = f1.i
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
} else {
i.Out = f1.i
- f.out = patchList(f.i<<1 | 1)
+ f.out = makePatchList(f.i<<1 | 1)
}
f1.out.patch(c.p, f.i)
return f
@@ -259,7 +249,7 @@ func (c *compiler) plus(f1 frag, nongreedy bool) frag {
func (c *compiler) empty(op EmptyOp) frag {
f := c.inst(InstEmptyWidth)
c.p.Inst[f.i].Arg = uint32(op)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
return f
}
@@ -273,7 +263,7 @@ func (c *compiler) rune(r []rune, flags Flags) frag {
flags &^= FoldCase
}
i.Arg = uint32(flags)
- f.out = patchList(f.i << 1)
+ f.out = makePatchList(f.i << 1)
// Special cases for exec machine.
switch {
diff --git a/src/run.bat b/src/run.bat
index 896c4ac3ec..c299671c13 100644
--- a/src/run.bat
+++ b/src/run.bat
@@ -1,59 +1,54 @@
-:: 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.
-
-@echo off
-
-if exist ..\bin\go.exe goto ok
-echo Must run run.bat from Go src directory after installing cmd/go.
-goto fail
-:ok
-
-:: Keep environment variables within this script
-:: unless invoked with --no-local.
-if x%1==x--no-local goto nolocal
-if x%2==x--no-local goto nolocal
-setlocal
-:nolocal
-
-set GOBUILDFAIL=0
-
-:: we disallow local import for non-local packages, if %GOROOT% happens
-:: to be under %GOPATH%, then some tests below will fail
-set GOPATH=
-:: Issue 14340: ignore GOBIN during all.bat.
-set GOBIN=
-set GOFLAGS=
-set GO111MODULE=
-
-rem TODO avoid rebuild if possible
-
-if x%1==x--no-rebuild goto norebuild
-echo ##### Building packages and commands.
-go install -a -v std cmd
-if errorlevel 1 goto fail
-echo.
-:norebuild
-
-:: we must unset GOROOT_FINAL before tests, because runtime/debug requires
-:: correct access to source code, so if we have GOROOT_FINAL in effect,
-:: at least runtime/debug test will fail.
-set GOROOT_FINAL=
-
-:: get CGO_ENABLED
-..\bin\go env > env.bat
-if errorlevel 1 goto fail
-call env.bat
-del env.bat
-echo.
-
-..\bin\go tool dist test
-if errorlevel 1 goto fail
-echo.
-
-goto end
-
-:fail
-set GOBUILDFAIL=1
-
-:end
+:: 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.
+
+@echo off
+
+if exist ..\bin\go.exe goto ok
+echo Must run run.bat from Go src directory after installing cmd/go.
+goto fail
+:ok
+
+:: Keep environment variables within this script
+:: unless invoked with --no-local.
+if x%1==x--no-local goto nolocal
+if x%2==x--no-local goto nolocal
+setlocal
+:nolocal
+
+set GOBUILDFAIL=0
+
+:: we disallow local import for non-local packages, if %GOROOT% happens
+:: to be under %GOPATH%, then some tests below will fail
+set GOPATH=
+:: Issue 14340: ignore GOBIN during all.bat.
+set GOBIN=
+set GOFLAGS=
+set GO111MODULE=
+
+rem TODO avoid rebuild if possible
+
+if x%1==x--no-rebuild goto norebuild
+echo ##### Building packages and commands.
+..\bin\go install -a -v std cmd
+if errorlevel 1 goto fail
+echo.
+:norebuild
+
+:: get CGO_ENABLED
+..\bin\go env > env.bat
+if errorlevel 1 goto fail
+call env.bat
+del env.bat
+echo.
+
+..\bin\go tool dist test
+if errorlevel 1 goto fail
+echo.
+
+goto end
+
+:fail
+set GOBUILDFAIL=1
+
+:end
diff --git a/src/runtime/cgo/gcc_android.c b/src/runtime/cgo/gcc_android.c
index 321a5150b9..7ea213599d 100644
--- a/src/runtime/cgo/gcc_android.c
+++ b/src/runtime/cgo/gcc_android.c
@@ -35,7 +35,7 @@ fatalf(const char* format, ...)
// Truncated to a different magic value on 32-bit; that's ok.
#define magic1 (0x23581321345589ULL)
-// From https://android.googlesource.com/platform/bionic/+/refs/heads/master/libc/private/bionic_asm_tls.h#69.
+// From https://android.googlesource.com/platform/bionic/+/refs/heads/android10-tests-release/libc/private/bionic_asm_tls.h#69.
#define TLS_SLOT_APP 2
// inittls allocates a thread-local storage slot for g.
diff --git a/src/runtime/cgo_sigaction.go b/src/runtime/cgo_sigaction.go
index bc5e0786d9..de634dc957 100644
--- a/src/runtime/cgo_sigaction.go
+++ b/src/runtime/cgo_sigaction.go
@@ -18,12 +18,12 @@ var _cgo_sigaction unsafe.Pointer
//go:nosplit
//go:nowritebarrierrec
func sigaction(sig uint32, new, old *sigactiont) {
- // The runtime package is explicitly blacklisted from sanitizer
- // instrumentation in racewalk.go, but we might be calling into instrumented C
- // functions here — so we need the pointer parameters to be properly marked.
+ // racewalk.go avoids adding sanitizing instrumentation to package runtime,
+ // but we might be calling into instrumented C functions here,
+ // so we need the pointer parameters to be properly marked.
//
- // Mark the input as having been written before the call and the output as
- // read after.
+ // Mark the input as having been written before the call
+ // and the output as read after.
if msanenabled && new != nil {
msanwrite(unsafe.Pointer(new), unsafe.Sizeof(*new))
}
diff --git a/src/runtime/crash_cgo_test.go b/src/runtime/crash_cgo_test.go
index a4d0ebfcd6..4872189f16 100644
--- a/src/runtime/crash_cgo_test.go
+++ b/src/runtime/crash_cgo_test.go
@@ -573,3 +573,30 @@ func TestSegv(t *testing.T) {
})
}
}
+
+// TestEINTR tests that we handle EINTR correctly.
+// See issue #20400 and friends.
+func TestEINTR(t *testing.T) {
+ switch runtime.GOOS {
+ case "plan9", "windows":
+ t.Skipf("no EINTR on %s", runtime.GOOS)
+ case "linux":
+ if runtime.GOARCH == "386" {
+ // On linux-386 the Go signal handler sets
+ // a restorer function that is not preserved
+ // by the C sigaction call in the test,
+ // causing the signal handler to crash when
+ // returning the normal code. The test is not
+ // architecture-specific, so just skip on 386
+ // rather than doing a complicated workaround.
+ t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
+ }
+ }
+
+ t.Parallel()
+ output := runTestProg(t, "testprogcgo", "EINTR")
+ want := "OK\n"
+ if output != want {
+ t.Fatalf("want %s, got %s\n", want, output)
+ }
+}
diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go
index 5333b60646..34f30c9a37 100644
--- a/src/runtime/crash_test.go
+++ b/src/runtime/crash_test.go
@@ -55,6 +55,16 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
t.Fatal(err)
}
+ return runBuiltTestProg(t, exe, name, env...)
+}
+
+func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string {
+ if *flagQuick {
+ t.Skip("-quick")
+ }
+
+ testenv.MustHaveGoBuild(t)
+
cmd := testenv.CleanCmdEnv(exec.Command(exe, name))
cmd.Env = append(cmd.Env, env...)
if testing.Short() {
@@ -64,7 +74,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
cmd.Stdout = &b
cmd.Stderr = &b
if err := cmd.Start(); err != nil {
- t.Fatalf("starting %s %s: %v", binary, name, err)
+ t.Fatalf("starting %s %s: %v", exe, name, err)
}
// If the process doesn't complete within 1 minute,
@@ -92,7 +102,7 @@ func runTestProg(t *testing.T, binary, name string, env ...string) string {
}()
if err := cmd.Wait(); err != nil {
- t.Logf("%s %s exit status: %v", binary, name, err)
+ t.Logf("%s %s exit status: %v", exe, name, err)
}
close(done)
diff --git a/src/runtime/debugcall.go b/src/runtime/debugcall.go
index 5cbe382ce7..6c285ec829 100644
--- a/src/runtime/debugcall.go
+++ b/src/runtime/debugcall.go
@@ -61,7 +61,7 @@ func debugCallCheck(pc uintptr) string {
"debugCall16384",
"debugCall32768",
"debugCall65536":
- // These functions are whitelisted so that the debugger can initiate multiple function calls.
+ // These functions are allowed so that the debugger can initiate multiple function calls.
// See: https://golang.org/cl/161137/
return
}
diff --git a/src/runtime/env_plan9.go b/src/runtime/env_plan9.go
index c95b5db510..b7ea863735 100644
--- a/src/runtime/env_plan9.go
+++ b/src/runtime/env_plan9.go
@@ -6,45 +6,117 @@ package runtime
import "unsafe"
-var tracebackbuf [128]byte
+const (
+ // Plan 9 environment device
+ envDir = "/env/"
+ // size of buffer to read from a directory
+ dirBufSize = 4096
+ // size of buffer to read an environment variable (may grow)
+ envBufSize = 128
+ // offset of the name field in a 9P directory entry - see syscall.UnmarshalDir()
+ nameOffset = 39
+)
-func gogetenv(key string) string {
- var file [128]byte
- if len(key) > len(file)-6 {
- return ""
+// Goenvs caches the Plan 9 environment variables at start of execution into
+// string array envs, to supply the initial contents for os.Environ.
+// Subsequent calls to os.Setenv will change this cache, without writing back
+// to the (possibly shared) Plan 9 environment, so that Setenv and Getenv
+// conform to the same Posix semantics as on other operating systems.
+// For Plan 9 shared environment semantics, instead of Getenv(key) and
+// Setenv(key, value), one can use ioutil.ReadFile("/env/" + key) and
+// ioutil.WriteFile("/env/" + key, value, 0666) respectively.
+//go:nosplit
+func goenvs() {
+ buf := make([]byte, envBufSize)
+ copy(buf, envDir)
+ dirfd := open(&buf[0], _OREAD, 0)
+ if dirfd < 0 {
+ return
}
+ defer closefd(dirfd)
+ dofiles(dirfd, func(name []byte) {
+ name = append(name, 0)
+ buf = buf[:len(envDir)]
+ copy(buf, envDir)
+ buf = append(buf, name...)
+ fd := open(&buf[0], _OREAD, 0)
+ if fd < 0 {
+ return
+ }
+ defer closefd(fd)
+ n := len(buf)
+ r := 0
+ for {
+ r = int(pread(fd, unsafe.Pointer(&buf[0]), int32(n), 0))
+ if r < n {
+ break
+ }
+ n = int(seek(fd, 0, 2)) + 1
+ if len(buf) < n {
+ buf = make([]byte, n)
+ }
+ }
+ if r <= 0 {
+ r = 0
+ } else if buf[r-1] == 0 {
+ r--
+ }
+ name[len(name)-1] = '='
+ env := make([]byte, len(name)+r)
+ copy(env, name)
+ copy(env[len(name):], buf[:r])
+ envs = append(envs, string(env))
+ })
+}
- copy(file[:], "/env/")
- copy(file[5:], key)
+// Dofiles reads the directory opened with file descriptor fd, applying function f
+// to each filename in it.
+//go:nosplit
+func dofiles(dirfd int32, f func([]byte)) {
+ dirbuf := new([dirBufSize]byte)
- fd := open(&file[0], _OREAD, 0)
- if fd < 0 {
- return ""
- }
- n := seek(fd, 0, 2)
- if n <= 0 {
- closefd(fd)
- return ""
+ var off int64 = 0
+ for {
+ n := pread(dirfd, unsafe.Pointer(&dirbuf[0]), int32(dirBufSize), off)
+ if n <= 0 {
+ return
+ }
+ for b := dirbuf[:n]; len(b) > 0; {
+ var name []byte
+ name, b = gdirname(b)
+ if name == nil {
+ return
+ }
+ f(name)
+ }
+ off += int64(n)
}
+}
- p := make([]byte, n)
-
- r := pread(fd, unsafe.Pointer(&p[0]), int32(n), 0)
- closefd(fd)
- if r < 0 {
- return ""
+// Gdirname returns the first filename from a buffer of directory entries,
+// and a slice containing the remaining directory entries.
+// If the buffer doesn't start with a valid directory entry, the returned name is nil.
+//go:nosplit
+func gdirname(buf []byte) (name []byte, rest []byte) {
+ if 2+nameOffset+2 > len(buf) {
+ return
}
-
- if p[r-1] == 0 {
- r--
+ entryLen, buf := gbit16(buf)
+ if entryLen > len(buf) {
+ return
}
-
- var s string
- sp := stringStructOf(&s)
- sp.str = unsafe.Pointer(&p[0])
- sp.len = int(r)
- return s
+ n, b := gbit16(buf[nameOffset:])
+ if n > len(b) {
+ return
+ }
+ name = b[:n]
+ rest = buf[entryLen:]
+ return
}
-var _cgo_setenv unsafe.Pointer // pointer to C function
-var _cgo_unsetenv unsafe.Pointer // pointer to C function
+// Gbit16 reads a 16-bit little-endian binary number from b and returns it
+// with the remaining slice of b.
+//go:nosplit
+func gbit16(b []byte) (int, []byte) {
+ return int(b[0]) | int(b[1])<<8, b[2:]
+}
diff --git a/src/runtime/env_posix.go b/src/runtime/env_posix.go
index f95ff68545..af353bbcd9 100644
--- a/src/runtime/env_posix.go
+++ b/src/runtime/env_posix.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 aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows
+// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris windows plan9
package runtime
diff --git a/src/runtime/env_test.go b/src/runtime/env_test.go
index 2399e46faa..c009d0f31e 100644
--- a/src/runtime/env_test.go
+++ b/src/runtime/env_test.go
@@ -11,10 +11,6 @@ import (
)
func TestFixedGOROOT(t *testing.T) {
- if runtime.GOOS == "plan9" {
- t.Skipf("skipping plan9, it is inconsistent by allowing GOROOT to be updated by Setenv")
- }
-
// Restore both the real GOROOT environment variable, and runtime's copies:
if orig, ok := syscall.Getenv("GOROOT"); ok {
defer syscall.Setenv("GOROOT", orig)
diff --git a/src/runtime/export_test.go b/src/runtime/export_test.go
index 4c1150acd4..5ab03f3f99 100644
--- a/src/runtime/export_test.go
+++ b/src/runtime/export_test.go
@@ -483,6 +483,8 @@ func GetNextArenaHint() uintptr {
type G = g
+type Sudog = sudog
+
func Getg() *G {
return getg()
}
@@ -733,9 +735,12 @@ func (p *PageAlloc) Free(base, npages uintptr) {
func (p *PageAlloc) Bounds() (ChunkIdx, ChunkIdx) {
return ChunkIdx((*pageAlloc)(p).start), ChunkIdx((*pageAlloc)(p).end)
}
-func (p *PageAlloc) Scavenge(nbytes uintptr, locked bool) (r uintptr) {
+func (p *PageAlloc) Scavenge(nbytes uintptr, mayUnlock bool) (r uintptr) {
+ pp := (*pageAlloc)(p)
systemstack(func() {
- r = (*pageAlloc)(p).scavenge(nbytes, locked)
+ lock(pp.mheapLock)
+ r = pp.scavenge(nbytes, mayUnlock)
+ unlock(pp.mheapLock)
})
return
}
@@ -743,8 +748,8 @@ func (p *PageAlloc) InUse() []AddrRange {
ranges := make([]AddrRange, 0, len(p.inUse.ranges))
for _, r := range p.inUse.ranges {
ranges = append(ranges, AddrRange{
- Base: r.base,
- Limit: r.limit,
+ Base: r.base.addr(),
+ Limit: r.limit.addr(),
})
}
return ranges
@@ -817,7 +822,6 @@ func NewPageAlloc(chunks, scav map[ChunkIdx][]BitRange) *PageAlloc {
}
}
}
- p.resetScavengeAddr()
// Apply alloc state.
for _, s := range init {
@@ -831,6 +835,11 @@ func NewPageAlloc(chunks, scav map[ChunkIdx][]BitRange) *PageAlloc {
// Update heap metadata for the allocRange calls above.
p.update(addr, pallocChunkPages, false, false)
}
+ systemstack(func() {
+ lock(p.mheapLock)
+ p.scavengeStartGen()
+ unlock(p.mheapLock)
+ })
return (*PageAlloc)(p)
}
@@ -867,13 +876,9 @@ func FreePageAlloc(pp *PageAlloc) {
// 64 bit and 32 bit platforms, allowing the tests to share code
// between the two.
//
-// On AIX, the arenaBaseOffset is 0x0a00000000000000. However, this
-// constant can't be used here because it is negative and will cause
-// a constant overflow.
-//
// This should not be higher than 0x100*pallocChunkBytes to support
// mips and mipsle, which only have 31-bit address spaces.
-var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + 0x0a00000000000000*sys.GoosAix))
+var BaseChunkIdx = ChunkIdx(chunkIndex(((0xc000*pageAlloc64Bit + 0x100*pageAlloc32Bit) * pallocChunkBytes) + arenaBaseOffset*sys.GoosAix))
// PageBase returns an address given a chunk index and a page index
// relative to that chunk.
diff --git a/src/runtime/extern.go b/src/runtime/extern.go
index 0ecc4eaf71..7316503ed2 100644
--- a/src/runtime/extern.go
+++ b/src/runtime/extern.go
@@ -87,7 +87,7 @@ It is a comma-separated list of name=val pairs setting these named variables:
When set to 0 memory profiling is disabled. Refer to the description of
MemProfileRate for the default value.
- invalidptr: defaults to invalidptr=1, causing the garbage collector and stack
+ invalidptr: invalidptr=1 (the default) causes the garbage collector and stack
copier to crash the program if an invalid pointer value (for example, 1)
is found in a pointer-typed location. Setting invalidptr=0 disables this check.
This should only be used as a temporary workaround to diagnose buggy code.
@@ -104,10 +104,11 @@ It is a comma-separated list of name=val pairs setting these named variables:
scavenger as well as the total amount of memory returned to the operating system
and an estimate of physical memory utilization. The format of this line is subject
to change, but currently it is:
- scav # KiB work, # KiB total, #% util
+ scav # # KiB work, # KiB total, #% util
where the fields are as follows:
- # KiB work the amount of memory returned to the OS since the last scav line
- # KiB total how much of the heap at this point in time has been released to the OS
+ scav # the scavenge cycle number
+ # KiB work the amount of memory returned to the OS since the last line
+ # KiB total the total amount of memory returned to the OS
#% util the fraction of all unscavenged memory which is in-use
If the line ends with "(forced)", then scavenging was forced by a
debug.FreeOSMemory() call.
diff --git a/src/runtime/gc_test.go b/src/runtime/gc_test.go
index 4c281ce52b..c5c8a4cecf 100644
--- a/src/runtime/gc_test.go
+++ b/src/runtime/gc_test.go
@@ -12,6 +12,7 @@ import (
"runtime"
"runtime/debug"
"sort"
+ "strings"
"sync"
"sync/atomic"
"testing"
@@ -192,6 +193,15 @@ func TestPeriodicGC(t *testing.T) {
}
}
+func TestGcZombieReporting(t *testing.T) {
+ // This test is somewhat sensitive to how the allocator works.
+ got := runTestProg(t, "testprog", "GCZombie")
+ want := "found pointer to free object"
+ if !strings.Contains(got, want) {
+ t.Fatalf("expected %q in output, but got %q", want, got)
+ }
+}
+
func BenchmarkSetTypePtr(b *testing.B) {
benchSetType(b, new(*byte))
}
diff --git a/src/runtime/hash_test.go b/src/runtime/hash_test.go
index 655ca18f11..502383557b 100644
--- a/src/runtime/hash_test.go
+++ b/src/runtime/hash_test.go
@@ -152,14 +152,13 @@ func (s *HashSet) addS_seed(x string, seed uintptr) {
s.add(StringHash(x, seed))
}
func (s *HashSet) check(t *testing.T) {
- const SLOP = 10.0
+ const SLOP = 50.0
collisions := s.n - len(s.m)
- //fmt.Printf("%d/%d\n", len(s.m), s.n)
pairs := int64(s.n) * int64(s.n-1) / 2
expected := float64(pairs) / math.Pow(2.0, float64(hashSize))
stddev := math.Sqrt(expected)
if float64(collisions) > expected+SLOP*(3*stddev+1) {
- t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f", collisions, expected, stddev)
+ t.Errorf("unexpected number of collisions: got=%d mean=%f stddev=%f threshold=%f", collisions, expected, stddev, expected+SLOP*(3*stddev+1))
}
}
@@ -564,8 +563,11 @@ func avalancheTest1(t *testing.T, k Key) {
// All bit rotations of a set of distinct keys
func TestSmhasherWindowed(t *testing.T) {
+ t.Logf("32 bit keys")
windowed(t, &Int32Key{})
+ t.Logf("64 bit keys")
windowed(t, &Int64Key{})
+ t.Logf("string keys")
windowed(t, &BytesKey{make([]byte, 128)})
}
func windowed(t *testing.T, k Key) {
diff --git a/src/runtime/lock_futex.go b/src/runtime/lock_futex.go
index b0395d6a69..91467fdfae 100644
--- a/src/runtime/lock_futex.go
+++ b/src/runtime/lock_futex.go
@@ -108,7 +108,7 @@ func lock2(l *mutex) {
}
func unlock(l *mutex) {
- lockRankRelease(l)
+ unlockWithRank(l)
}
func unlock2(l *mutex) {
@@ -238,8 +238,8 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
-func beforeIdle(int64) bool {
- return false
+func beforeIdle(int64) (*g, bool) {
+ return nil, false
}
func checkTimeouts() {}
diff --git a/src/runtime/lock_js.go b/src/runtime/lock_js.go
index 7a720f4790..14bdc76842 100644
--- a/src/runtime/lock_js.go
+++ b/src/runtime/lock_js.go
@@ -44,7 +44,7 @@ func lock2(l *mutex) {
}
func unlock(l *mutex) {
- lockRankRelease(l)
+ unlockWithRank(l)
}
func unlock2(l *mutex) {
@@ -173,7 +173,9 @@ var idleID int32
// beforeIdle gets called by the scheduler if no goroutine is awake.
// If we are not already handling an event, then we pause for an async event.
// If an event handler returned, we resume it and it will pause the execution.
-func beforeIdle(delay int64) bool {
+// beforeIdle either returns the specific goroutine to schedule next or
+// indicates with otherReady that some goroutine became ready.
+func beforeIdle(delay int64) (gp *g, otherReady bool) {
if delay > 0 {
clearIdleID()
if delay < 1e6 {
@@ -190,15 +192,14 @@ func beforeIdle(delay int64) bool {
if len(events) == 0 {
go handleAsyncEvent()
- return true
+ return nil, true
}
e := events[len(events)-1]
if e.returned {
- goready(e.gp, 1)
- return true
+ return e.gp, false
}
- return false
+ return nil, false
}
func handleAsyncEvent() {
diff --git a/src/runtime/lock_sema.go b/src/runtime/lock_sema.go
index d79520da07..671e524e45 100644
--- a/src/runtime/lock_sema.go
+++ b/src/runtime/lock_sema.go
@@ -94,7 +94,7 @@ Loop:
}
func unlock(l *mutex) {
- lockRankRelease(l)
+ unlockWithRank(l)
}
//go:nowritebarrier
@@ -297,8 +297,8 @@ func notetsleepg(n *note, ns int64) bool {
return ok
}
-func beforeIdle(int64) bool {
- return false
+func beforeIdle(int64) (*g, bool) {
+ return nil, false
}
func checkTimeouts() {}
diff --git a/src/runtime/lockrank.go b/src/runtime/lockrank.go
index 5174adc8bf..000193585d 100644
--- a/src/runtime/lockrank.go
+++ b/src/runtime/lockrank.go
@@ -33,6 +33,7 @@ const (
lockRankDummy lockRank = iota
// Locks held above sched
+ lockRankSysmon
lockRankScavenge
lockRankForcegc
lockRankSweepWaiters
@@ -69,6 +70,7 @@ const (
lockRankMcentral // For !go115NewMCentralImpl
lockRankSpine // For !go115NewMCentralImpl
lockRankSpanSetSpine
+ lockRankGscan
lockRankStackpool
lockRankStackLarge
lockRankDefer
@@ -84,6 +86,14 @@ const (
// Other leaf locks
lockRankGFree
+ // Generally, hchan must be acquired before gscan. But in one specific
+ // case (in syncadjustsudogs from markroot after the g has been suspended
+ // by suspendG), we allow gscan to be acquired, and then an hchan lock. To
+ // allow this case, we get this lockRankHchanLeaf rank in
+ // syncadjustsudogs(), rather than lockRankHchan. By using this special
+ // rank, we don't allow any further locks to be acquired other than more
+ // hchan locks.
+ lockRankHchanLeaf
// Leaf locks with no dependencies, so these constants are not actually used anywhere.
// There are other architecture-dependent leaf locks as well.
@@ -104,6 +114,7 @@ const lockRankLeafRank lockRank = 1000
var lockNames = []string{
lockRankDummy: "",
+ lockRankSysmon: "sysmon",
lockRankScavenge: "scavenge",
lockRankForcegc: "forcegc",
lockRankSweepWaiters: "sweepWaiters",
@@ -141,6 +152,7 @@ var lockNames = []string{
lockRankMcentral: "mcentral",
lockRankSpine: "spine",
lockRankSpanSetSpine: "spanSetSpine",
+ lockRankGscan: "gscan",
lockRankStackpool: "stackpool",
lockRankStackLarge: "stackLarge",
lockRankDefer: "defer",
@@ -152,7 +164,8 @@ var lockNames = []string{
lockRankGlobalAlloc: "globalAlloc.mutex",
- lockRankGFree: "gFree",
+ lockRankGFree: "gFree",
+ lockRankHchanLeaf: "hchanLeaf",
lockRankNewmHandoff: "newmHandoff.lock",
lockRankDebugPtrmask: "debugPtrmask.lock",
@@ -183,50 +196,53 @@ func (rank lockRank) String() string {
// hchan lock can be held immediately above it when it is acquired.
var lockPartialOrder [][]lockRank = [][]lockRank{
lockRankDummy: {},
- lockRankScavenge: {},
- lockRankForcegc: {},
+ lockRankSysmon: {},
+ lockRankScavenge: {lockRankSysmon},
+ lockRankForcegc: {lockRankSysmon},
lockRankSweepWaiters: {},
lockRankAssistQueue: {},
lockRankCpuprof: {},
lockRankSweep: {},
- lockRankSched: {lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
+ lockRankSched: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep},
lockRankDeadlock: {lockRankDeadlock},
lockRankPanic: {lockRankDeadlock},
- lockRankAllg: {lockRankSched, lockRankPanic},
- lockRankAllp: {lockRankSched},
+ lockRankAllg: {lockRankSysmon, lockRankSched, lockRankPanic},
+ lockRankAllp: {lockRankSysmon, lockRankSched},
lockRankPollDesc: {},
- lockRankTimers: {lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
+ lockRankTimers: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllp, lockRankPollDesc, lockRankTimers},
lockRankItab: {},
lockRankReflectOffs: {lockRankItab},
lockRankHchan: {lockRankScavenge, lockRankSweep, lockRankHchan},
- lockRankFin: {lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan},
+ lockRankFin: {lockRankSysmon, lockRankScavenge, lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan},
lockRankNotifyList: {},
- lockRankTraceBuf: {lockRankScavenge},
+ lockRankTraceBuf: {lockRankSysmon, lockRankScavenge},
lockRankTraceStrings: {lockRankTraceBuf},
- lockRankMspanSpecial: {lockRankScavenge, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings},
- lockRankProf: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
- lockRankGcBitsArenas: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankMspanSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings},
+ lockRankProf: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankGcBitsArenas: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
lockRankRoot: {},
- lockRankTrace: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankSweep},
+ lockRankTrace: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankSched, lockRankHchan, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankSweep},
lockRankTraceStackTab: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankTimers, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankTrace},
lockRankNetpollInit: {lockRankTimers},
lockRankRwmutexW: {},
lockRankRwmutexR: {lockRankRwmutexW},
- lockRankMcentral: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
- lockRankSpine: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
- lockRankSpanSetSpine: {lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
- lockRankStackpool: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine},
- lockRankStackLarge: {lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine},
+ lockRankMcentral: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankSpine: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSched, lockRankAllg, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankSpanSetSpine: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankGscan: {lockRankSysmon, lockRankScavenge, lockRankForcegc, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankTraceBuf, lockRankTraceStrings, lockRankRoot, lockRankNotifyList, lockRankProf, lockRankGcBitsArenas, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine},
+ lockRankStackpool: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankFin, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankTrace, lockRankTraceStackTab, lockRankNetpollInit, lockRankRwmutexR, lockRankMcentral, lockRankSpine, lockRankSpanSetSpine, lockRankGscan},
+ lockRankStackLarge: {lockRankSysmon, lockRankAssistQueue, lockRankSched, lockRankItab, lockRankHchan, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankSpanSetSpine, lockRankGscan},
lockRankDefer: {},
lockRankSudog: {lockRankNotifyList, lockRankHchan},
- lockRankWbufSpans: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankDefer, lockRankSudog},
- lockRankMheap: {lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine},
- lockRankMheapSpecial: {lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
+ lockRankWbufSpans: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankSweep, lockRankSched, lockRankAllg, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankHchan, lockRankNotifyList, lockRankTraceStrings, lockRankMspanSpecial, lockRankProf, lockRankRoot, lockRankGscan, lockRankDefer, lockRankSudog},
+ lockRankMheap: {lockRankSysmon, lockRankScavenge, lockRankSweepWaiters, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankPollDesc, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan, lockRankMspanSpecial, lockRankProf, lockRankGcBitsArenas, lockRankRoot, lockRankMcentral, lockRankGscan, lockRankStackpool, lockRankStackLarge, lockRankDefer, lockRankSudog, lockRankWbufSpans, lockRankSpanSetSpine},
+ lockRankMheapSpecial: {lockRankSysmon, lockRankScavenge, lockRankAssistQueue, lockRankCpuprof, lockRankSweep, lockRankSched, lockRankAllg, lockRankAllp, lockRankTimers, lockRankItab, lockRankReflectOffs, lockRankNotifyList, lockRankTraceBuf, lockRankTraceStrings, lockRankHchan},
lockRankGlobalAlloc: {lockRankProf, lockRankSpine, lockRankSpanSetSpine, lockRankMheap, lockRankMheapSpecial},
- lockRankGFree: {lockRankSched},
+ lockRankGFree: {lockRankSched},
+ lockRankHchanLeaf: {lockRankGscan, lockRankHchanLeaf},
lockRankNewmHandoff: {},
lockRankDebugPtrmask: {},
diff --git a/src/runtime/lockrank_off.go b/src/runtime/lockrank_off.go
index fcfcff57a3..891589c0f2 100644
--- a/src/runtime/lockrank_off.go
+++ b/src/runtime/lockrank_off.go
@@ -14,12 +14,18 @@ func getLockRank(l *mutex) lockRank {
return 0
}
-func lockRankRelease(l *mutex) {
+func lockWithRank(l *mutex, rank lockRank) {
+ lock2(l)
+}
+
+func acquireLockRank(rank lockRank) {
+}
+
+func unlockWithRank(l *mutex) {
unlock2(l)
}
-func lockWithRank(l *mutex, rank lockRank) {
- lock2(l)
+func releaseLockRank(rank lockRank) {
}
func lockWithRankMayAcquire(l *mutex, rank lockRank) {
diff --git a/src/runtime/lockrank_on.go b/src/runtime/lockrank_on.go
index fc72a06f6f..cf4151ff46 100644
--- a/src/runtime/lockrank_on.go
+++ b/src/runtime/lockrank_on.go
@@ -46,10 +46,17 @@ func getLockRank(l *mutex) lockRank {
// when acquiring a non-static lock.
//go:nosplit
func lockWithRank(l *mutex, rank lockRank) {
- if l == &debuglock {
- // debuglock is only used for println/printlock(). Don't do lock rank
- // recording for it, since print/println are used when printing
- // out a lock ordering problem below.
+ if l == &debuglock || l == &paniclk {
+ // debuglock is only used for println/printlock(). Don't do lock
+ // rank recording for it, since print/println are used when
+ // printing out a lock ordering problem below.
+ //
+ // paniclk has an ordering problem, since it can be acquired
+ // during a panic with any other locks held (especially if the
+ // panic is because of a directed segv), and yet also allg is
+ // acquired after paniclk in tracebackothers()). This is a genuine
+ // problem, so for now we don't do lock rank recording for paniclk
+ // either.
lock2(l)
return
}
@@ -75,26 +82,49 @@ func lockWithRank(l *mutex, rank lockRank) {
})
}
+// acquireLockRank acquires a rank which is not associated with a mutex lock
+//go:nosplit
+func acquireLockRank(rank lockRank) {
+ gp := getg()
+ // Log the new class.
+ systemstack(func() {
+ i := gp.m.locksHeldLen
+ if i >= len(gp.m.locksHeld) {
+ throw("too many locks held concurrently for rank checking")
+ }
+ gp.m.locksHeld[i].rank = rank
+ gp.m.locksHeld[i].lockAddr = 0
+ gp.m.locksHeldLen++
+
+ // i is the index of the lock being acquired
+ if i > 0 {
+ checkRanks(gp, gp.m.locksHeld[i-1].rank, rank)
+ }
+ })
+}
+
+// checkRanks checks if goroutine g, which has mostly recently acquired a lock
+// with rank 'prevRank', can now acquire a lock with rank 'rank'.
func checkRanks(gp *g, prevRank, rank lockRank) {
rankOK := false
- // If rank < prevRank, then we definitely have a rank error
- if prevRank <= rank {
- if rank == lockRankLeafRank {
- // If new lock is a leaf lock, then the preceding lock can
- // be anything except another leaf lock.
- rankOK = prevRank < lockRankLeafRank
- } else {
- // We've already verified the total lock ranking, but we
- // also enforce the partial ordering specified by
- // lockPartialOrder as well. Two locks with the same rank
- // can only be acquired at the same time if explicitly
- // listed in the lockPartialOrder table.
- list := lockPartialOrder[rank]
- for _, entry := range list {
- if entry == prevRank {
- rankOK = true
- break
- }
+ if rank < prevRank {
+ // If rank < prevRank, then we definitely have a rank error
+ rankOK = false
+ } else if rank == lockRankLeafRank {
+ // If new lock is a leaf lock, then the preceding lock can
+ // be anything except another leaf lock.
+ rankOK = prevRank < lockRankLeafRank
+ } else {
+ // We've now verified the total lock ranking, but we
+ // also enforce the partial ordering specified by
+ // lockPartialOrder as well. Two locks with the same rank
+ // can only be acquired at the same time if explicitly
+ // listed in the lockPartialOrder table.
+ list := lockPartialOrder[rank]
+ for _, entry := range list {
+ if entry == prevRank {
+ rankOK = true
+ break
}
}
}
@@ -109,11 +139,9 @@ func checkRanks(gp *g, prevRank, rank lockRank) {
}
//go:nosplit
-func lockRankRelease(l *mutex) {
- if l == &debuglock {
- // debuglock is only used for print/println. Don't do lock rank
- // recording for it, since print/println are used when printing
- // out a lock ordering problem below.
+func unlockWithRank(l *mutex) {
+ if l == &debuglock || l == &paniclk {
+ // See comment at beginning of lockWithRank.
unlock2(l)
return
}
@@ -125,6 +153,7 @@ func lockRankRelease(l *mutex) {
found = true
copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
gp.m.locksHeldLen--
+ break
}
}
if !found {
@@ -135,6 +164,27 @@ func lockRankRelease(l *mutex) {
})
}
+// releaseLockRank releases a rank which is not associated with a mutex lock
+//go:nosplit
+func releaseLockRank(rank lockRank) {
+ gp := getg()
+ systemstack(func() {
+ found := false
+ for i := gp.m.locksHeldLen - 1; i >= 0; i-- {
+ if gp.m.locksHeld[i].rank == rank && gp.m.locksHeld[i].lockAddr == 0 {
+ found = true
+ copy(gp.m.locksHeld[i:gp.m.locksHeldLen-1], gp.m.locksHeld[i+1:gp.m.locksHeldLen])
+ gp.m.locksHeldLen--
+ break
+ }
+ }
+ if !found {
+ println(gp.m.procid, ":", rank.String(), rank)
+ throw("lockRank release without matching lockRank acquire")
+ }
+ })
+}
+
//go:nosplit
func lockWithRankMayAcquire(l *mutex, rank lockRank) {
gp := getg()
diff --git a/src/runtime/malloc.go b/src/runtime/malloc.go
index 2da694d14a..b3fac3de24 100644
--- a/src/runtime/malloc.go
+++ b/src/runtime/malloc.go
@@ -302,7 +302,9 @@ const (
//
// On other platforms, the user address space is contiguous
// and starts at 0, so no offset is necessary.
- arenaBaseOffset = sys.GoarchAmd64*(1<<47) + (^0x0a00000000000000+1)&uintptrMask*sys.GoosAix
+ arenaBaseOffset = 0xffff800000000000*sys.GoarchAmd64 + 0x0a00000000000000*sys.GoosAix
+ // A typed version of this constant that will make it into DWARF (for viewcore).
+ arenaBaseOffsetUintptr = uintptr(arenaBaseOffset)
// Max number of threads to run garbage collection.
// 2, 3, and 4 are all plausible maximums depending
@@ -604,7 +606,7 @@ func mallocinit() {
a, size := sysReserveAligned(unsafe.Pointer(p), arenaSize, heapArenaBytes)
if a != nil {
mheap_.arena.init(uintptr(a), size)
- p = uintptr(a) + size // For hint below
+ p = mheap_.arena.end // For hint below
break
}
}
@@ -976,6 +978,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
throw("malloc called with no P")
}
}
+ var span *mspan
var x unsafe.Pointer
noscan := typ == nil || typ.ptrdata == 0
if size <= maxSmallSize {
@@ -1028,10 +1031,10 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
return x
}
// Allocate a new maxTinySize block.
- span := c.alloc[tinySpanClass]
+ span = c.alloc[tinySpanClass]
v := nextFreeFast(span)
if v == 0 {
- v, _, shouldhelpgc = c.nextFree(tinySpanClass)
+ v, span, shouldhelpgc = c.nextFree(tinySpanClass)
}
x = unsafe.Pointer(v)
(*[2]uint64)(x)[0] = 0
@@ -1052,7 +1055,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
}
size = uintptr(class_to_size[sizeclass])
spc := makeSpanClass(sizeclass, noscan)
- span := c.alloc[spc]
+ span = c.alloc[spc]
v := nextFreeFast(span)
if v == 0 {
v, span, shouldhelpgc = c.nextFree(spc)
@@ -1063,15 +1066,14 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
}
}
} else {
- var s *mspan
shouldhelpgc = true
systemstack(func() {
- s = largeAlloc(size, needzero, noscan)
+ span = largeAlloc(size, needzero, noscan)
})
- s.freeindex = 1
- s.allocCount = 1
- x = unsafe.Pointer(s.base())
- size = s.elemsize
+ span.freeindex = 1
+ span.allocCount = 1
+ x = unsafe.Pointer(span.base())
+ size = span.elemsize
}
var scanSize uintptr
@@ -1112,7 +1114,7 @@ func mallocgc(size uintptr, typ *_type, needzero bool) unsafe.Pointer {
// This may be racing with GC so do it atomically if there can be
// a race marking the bit.
if gcphase != _GCoff {
- gcmarknewobject(uintptr(x), size, scanSize)
+ gcmarknewobject(span, uintptr(x), size, scanSize)
}
if raceenabled {
@@ -1423,6 +1425,13 @@ type linearAlloc struct {
}
func (l *linearAlloc) init(base, size uintptr) {
+ if base+size < base {
+ // Chop off the last byte. The runtime isn't prepared
+ // to deal with situations where the bounds could overflow.
+ // Leave that memory reserved, though, so we don't map it
+ // later.
+ size -= 1
+ }
l.next, l.mapped = base, base
l.end = base + size
}
diff --git a/src/runtime/memclr_arm.s b/src/runtime/memclr_arm.s
index ea3c67afc5..7326b8be34 100644
--- a/src/runtime/memclr_arm.s
+++ b/src/runtime/memclr_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memset-arm.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memset-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memset-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_386.s b/src/runtime/memmove_386.s
index ecadee39af..d99546c633 100644
--- a/src/runtime/memmove_386.s
+++ b/src/runtime/memmove_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-386.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_amd64.s b/src/runtime/memmove_amd64.s
index 9458351fec..d91641a8e8 100644
--- a/src/runtime/memmove_amd64.s
+++ b/src/runtime/memmove_amd64.s
@@ -1,5 +1,5 @@
// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_arm.s b/src/runtime/memmove_arm.s
index 7bad8d2249..43d53fa8f2 100644
--- a/src/runtime/memmove_arm.s
+++ b/src/runtime/memmove_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-arm.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memmove-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_plan9_386.s b/src/runtime/memmove_plan9_386.s
index 1b2f8470ae..cfce0e966e 100644
--- a/src/runtime/memmove_plan9_386.s
+++ b/src/runtime/memmove_plan9_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/memmove-386.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/memmove_plan9_amd64.s b/src/runtime/memmove_plan9_amd64.s
index 68e11d59fd..217aa60468 100644
--- a/src/runtime/memmove_plan9_amd64.s
+++ b/src/runtime/memmove_plan9_amd64.s
@@ -1,5 +1,5 @@
// Derived from Inferno's libkern/memmove-386.s (adapted for amd64)
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/memmove-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/memmove-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/mgcmark.go b/src/runtime/mgcmark.go
index dafb4634b4..fe988c46d9 100644
--- a/src/runtime/mgcmark.go
+++ b/src/runtime/mgcmark.go
@@ -1627,11 +1627,21 @@ func gcDumpObject(label string, obj, off uintptr) {
//
//go:nowritebarrier
//go:nosplit
-func gcmarknewobject(obj, size, scanSize uintptr) {
+func gcmarknewobject(span *mspan, obj, size, scanSize uintptr) {
if useCheckmark { // The world should be stopped so this should not happen.
throw("gcmarknewobject called while doing checkmark")
}
- markBitsForAddr(obj).setMarked()
+
+ // Mark object.
+ objIndex := span.objIndex(obj)
+ span.markBitsForIndex(objIndex).setMarked()
+
+ // Mark span.
+ arena, pageIdx, pageMask := pageIndexOf(span.base())
+ if arena.pageMarks[pageIdx]&pageMask == 0 {
+ atomic.Or8(&arena.pageMarks[pageIdx], pageMask)
+ }
+
gcw := &getg().m.p.ptr().gcw
gcw.bytesMarked += uint64(size)
gcw.scanWork += int64(scanSize)
diff --git a/src/runtime/mgcscavenge.go b/src/runtime/mgcscavenge.go
index 1392136617..b74da1057a 100644
--- a/src/runtime/mgcscavenge.go
+++ b/src/runtime/mgcscavenge.go
@@ -91,6 +91,11 @@ const (
// This ratio is used as part of multiplicative factor to help the scavenger account
// for the additional costs of using scavenged memory in its pacing.
scavengeCostRatio = 0.7 * sys.GoosDarwin
+
+ // scavengeReservationShards determines the amount of memory the scavenger
+ // should reserve for scavenging at a time. Specifically, the amount of
+ // memory reserved is (heap size in bytes) / scavengeReservationShards.
+ scavengeReservationShards = 64
)
// heapRetained returns an estimate of the current heap RSS.
@@ -293,13 +298,14 @@ func bgscavenge(c chan int) {
unlock(&mheap_.lock)
return
}
- unlock(&mheap_.lock)
// Scavenge one page, and measure the amount of time spent scavenging.
start := nanotime()
- released = mheap_.pages.scavengeOne(physPageSize, false)
- atomic.Xadduintptr(&mheap_.pages.scavReleased, released)
+ released = mheap_.pages.scavenge(physPageSize, true)
+ mheap_.pages.scav.released += released
crit = float64(nanotime() - start)
+
+ unlock(&mheap_.lock)
})
if released == 0 {
@@ -379,28 +385,36 @@ func bgscavenge(c chan int) {
// scavenge scavenges nbytes worth of free pages, starting with the
// highest address first. Successive calls continue from where it left
-// off until the heap is exhausted. Call resetScavengeAddr to bring it
+// off until the heap is exhausted. Call scavengeStartGen to bring it
// back to the top of the heap.
//
// Returns the amount of memory scavenged in bytes.
//
-// If locked == false, s.mheapLock must not be locked. If locked == true,
-// s.mheapLock must be locked.
+// s.mheapLock must be held, but may be temporarily released if
+// mayUnlock == true.
//
-// Must run on the system stack because scavengeOne must run on the
-// system stack.
+// Must run on the system stack because s.mheapLock must be held.
//
//go:systemstack
-func (s *pageAlloc) scavenge(nbytes uintptr, locked bool) uintptr {
+func (s *pageAlloc) scavenge(nbytes uintptr, mayUnlock bool) uintptr {
+ var (
+ addrs addrRange
+ gen uint32
+ )
released := uintptr(0)
for released < nbytes {
- r := s.scavengeOne(nbytes-released, locked)
- if r == 0 {
- // Nothing left to scavenge! Give up.
- break
+ if addrs.size() == 0 {
+ if addrs, gen = s.scavengeReserve(); addrs.size() == 0 {
+ break
+ }
}
+ r, a := s.scavengeOne(addrs, nbytes-released, mayUnlock)
released += r
+ addrs = a
}
+ // Only unreserve the space which hasn't been scavenged or searched
+ // to ensure we always make progress.
+ s.scavengeUnreserve(addrs, gen)
return released
}
@@ -409,9 +423,9 @@ func (s *pageAlloc) scavenge(nbytes uintptr, locked bool) uintptr {
// released should be the amount of memory released since the last time this
// was called, and forced indicates whether the scavenge was forced by the
// application.
-func printScavTrace(released uintptr, forced bool) {
+func printScavTrace(gen uint32, released uintptr, forced bool) {
printlock()
- print("scav ",
+ print("scav ", gen, " ",
released>>10, " KiB work, ",
atomic.Load64(&memstats.heap_released)>>10, " KiB total, ",
(atomic.Load64(&memstats.heap_inuse)*100)/heapRetained(), "% util",
@@ -423,38 +437,131 @@ func printScavTrace(released uintptr, forced bool) {
printunlock()
}
-// resetScavengeAddr sets the scavenge start address to the top of the heap's
-// address space. This should be called whenever the sweeper is done.
+// scavengeStartGen starts a new scavenge generation, resetting
+// the scavenger's search space to the full in-use address space.
//
// s.mheapLock must be held.
-func (s *pageAlloc) resetScavengeAddr() {
- released := atomic.Loaduintptr(&s.scavReleased)
+//
+// Must run on the system stack because s.mheapLock must be held.
+//
+//go:systemstack
+func (s *pageAlloc) scavengeStartGen() {
if debug.scavtrace > 0 {
- printScavTrace(released, false)
+ printScavTrace(s.scav.gen, s.scav.released, false)
+ }
+ s.inUse.cloneInto(&s.scav.inUse)
+
+ // Pick the new starting address for the scavenger cycle.
+ var startAddr offAddr
+ if s.scav.scavLWM.lessThan(s.scav.freeHWM) {
+ // The "free" high watermark exceeds the "scavenged" low watermark,
+ // so there are free scavengable pages in parts of the address space
+ // that the scavenger already searched, the high watermark being the
+ // highest one. Pick that as our new starting point to ensure we
+ // see those pages.
+ startAddr = s.scav.freeHWM
+ } else {
+ // The "free" high watermark does not exceed the "scavenged" low
+ // watermark. This means the allocator didn't free any memory in
+ // the range we scavenged last cycle, so we might as well continue
+ // scavenging from where we were.
+ startAddr = s.scav.scavLWM
+ }
+ s.scav.inUse.removeGreaterEqual(startAddr.addr())
+
+ // reservationBytes may be zero if s.inUse.totalBytes is small, or if
+ // scavengeReservationShards is large. This case is fine as the scavenger
+ // will simply be turned off, but it does mean that scavengeReservationShards,
+ // in concert with pallocChunkBytes, dictates the minimum heap size at which
+ // the scavenger triggers. In practice this minimum is generally less than an
+ // arena in size, so virtually every heap has the scavenger on.
+ s.scav.reservationBytes = alignUp(s.inUse.totalBytes, pallocChunkBytes) / scavengeReservationShards
+ s.scav.gen++
+ s.scav.released = 0
+ s.scav.freeHWM = minOffAddr
+ s.scav.scavLWM = maxOffAddr
+}
+
+// scavengeReserve reserves a contiguous range of the address space
+// for scavenging. The maximum amount of space it reserves is proportional
+// to the size of the heap. The ranges are reserved from the high addresses
+// first.
+//
+// Returns the reserved range and the scavenge generation number for it.
+//
+// s.mheapLock must be held.
+//
+// Must run on the system stack because s.mheapLock must be held.
+//
+//go:systemstack
+func (s *pageAlloc) scavengeReserve() (addrRange, uint32) {
+ // Start by reserving the minimum.
+ r := s.scav.inUse.removeLast(s.scav.reservationBytes)
+
+ // Return early if the size is zero; we don't want to use
+ // the bogus address below.
+ if r.size() == 0 {
+ return r, s.scav.gen
+ }
+
+ // The scavenger requires that base be aligned to a
+ // palloc chunk because that's the unit of operation for
+ // the scavenger, so align down, potentially extending
+ // the range.
+ newBase := alignDown(r.base.addr(), pallocChunkBytes)
+
+ // Remove from inUse however much extra we just pulled out.
+ s.scav.inUse.removeGreaterEqual(newBase)
+ r.base = offAddr{newBase}
+ return r, s.scav.gen
+}
+
+// scavengeUnreserve returns an unscavenged portion of a range that was
+// previously reserved with scavengeReserve.
+//
+// s.mheapLock must be held.
+//
+// Must run on the system stack because s.mheapLock must be held.
+//
+//go:systemstack
+func (s *pageAlloc) scavengeUnreserve(r addrRange, gen uint32) {
+ if r.size() == 0 || gen != s.scav.gen {
+ return
+ }
+ if r.base.addr()%pallocChunkBytes != 0 {
+ throw("unreserving unaligned region")
}
- // Subtract from scavReleased instead of just setting it to zero because
- // the scavenger could have increased scavReleased concurrently with the
- // load above, and we may miss an update by just blindly zeroing the field.
- atomic.Xadduintptr(&s.scavReleased, -released)
- s.scavAddr = chunkBase(s.end) - 1
+ s.scav.inUse.add(r)
}
-// scavengeOne starts from s.scavAddr and walks down the heap until it finds
-// a contiguous run of pages to scavenge. It will try to scavenge at most
-// max bytes at once, but may scavenge more to avoid breaking huge pages. Once
-// it scavenges some memory it returns how much it scavenged and updates s.scavAddr
-// appropriately. s.scavAddr must be reset manually and externally.
+// scavengeOne walks over address range work until it finds
+// a contiguous run of pages to scavenge. It will try to scavenge
+// at most max bytes at once, but may scavenge more to avoid
+// breaking huge pages. Once it scavenges some memory it returns
+// how much it scavenged in bytes.
//
-// Should it exhaust the heap, it will return 0 and set s.scavAddr to minScavAddr.
+// Returns the number of bytes scavenged and the part of work
+// which was not yet searched.
//
-// If locked == false, s.mheapLock must not be locked.
-// If locked == true, s.mheapLock must be locked.
+// work's base address must be aligned to pallocChunkBytes.
//
-// Must be run on the system stack because it either acquires the heap lock
-// or executes with the heap lock acquired.
+// s.mheapLock must be held, but may be temporarily released if
+// mayUnlock == true.
+//
+// Must run on the system stack because s.mheapLock must be held.
//
//go:systemstack
-func (s *pageAlloc) scavengeOne(max uintptr, locked bool) uintptr {
+func (s *pageAlloc) scavengeOne(work addrRange, max uintptr, mayUnlock bool) (uintptr, addrRange) {
+ // Defensively check if we've recieved an empty address range.
+ // If so, just return.
+ if work.size() == 0 {
+ // Nothing to do.
+ return 0, work
+ }
+ // Check the prerequisites of work.
+ if work.base.addr()%pallocChunkBytes != 0 {
+ throw("scavengeOne called with unaligned work region")
+ }
// Calculate the maximum number of pages to scavenge.
//
// This should be alignUp(max, pageSize) / pageSize but max can and will
@@ -476,84 +583,49 @@ func (s *pageAlloc) scavengeOne(max uintptr, locked bool) uintptr {
minPages = 1
}
- // Helpers for locking and unlocking only if locked == false.
+ // Helpers for locking and unlocking only if mayUnlock == true.
lockHeap := func() {
- if !locked {
+ if mayUnlock {
lock(s.mheapLock)
}
}
unlockHeap := func() {
- if !locked {
+ if mayUnlock {
unlock(s.mheapLock)
}
}
- lockHeap()
- ci := chunkIndex(s.scavAddr)
- if ci < s.start {
- unlockHeap()
- return 0
- }
-
- // Check the chunk containing the scav addr, starting at the addr
- // and see if there are any free and unscavenged pages.
+ // Fast path: check the chunk containing the top-most address in work,
+ // starting at that address's page index in the chunk.
//
- // Only check this if s.scavAddr is covered by any address range
- // in s.inUse, so that we know our check of the summary is safe.
- if s.inUse.contains(s.scavAddr) && s.summary[len(s.summary)-1][ci].max() >= uint(minPages) {
+ // Note that work.end() is exclusive, so get the chunk we care about
+ // by subtracting 1.
+ maxAddr := work.limit.addr() - 1
+ maxChunk := chunkIndex(maxAddr)
+ if s.summary[len(s.summary)-1][maxChunk].max() >= uint(minPages) {
// We only bother looking for a candidate if there at least
- // minPages free pages at all. It's important that we only
- // continue if the summary says we can because that's how
- // we can tell if parts of the address space are unused.
- // See the comment on s.chunks in mpagealloc.go.
- base, npages := s.chunkOf(ci).findScavengeCandidate(chunkPageIndex(s.scavAddr), minPages, maxPages)
+ // minPages free pages at all.
+ base, npages := s.chunkOf(maxChunk).findScavengeCandidate(chunkPageIndex(maxAddr), minPages, maxPages)
// If we found something, scavenge it and return!
if npages != 0 {
- s.scavengeRangeLocked(ci, base, npages)
- unlockHeap()
- return uintptr(npages) * pageSize
+ work.limit = offAddr{s.scavengeRangeLocked(maxChunk, base, npages)}
+ return uintptr(npages) * pageSize, work
}
}
+ // Update the limit to reflect the fact that we checked maxChunk already.
+ work.limit = offAddr{chunkBase(maxChunk)}
- // getInUseRange returns the highest range in the
- // intersection of [0, addr] and s.inUse.
+ // findCandidate finds the next scavenge candidate in work optimistically.
//
- // s.mheapLock must be held.
- getInUseRange := func(addr uintptr) addrRange {
- top := s.inUse.findSucc(addr)
- if top == 0 {
- return addrRange{}
- }
- r := s.inUse.ranges[top-1]
- // addr is inclusive, so treat it as such when
- // updating the limit, which is exclusive.
- if r.limit > addr+1 {
- r.limit = addr + 1
- }
- return r
- }
-
- // Slow path: iterate optimistically over the in-use address space
- // looking for any free and unscavenged page. If we think we see something,
- // lock and verify it!
+ // Returns the candidate chunk index and true on success, and false on failure.
//
- // We iterate over the address space by taking ranges from inUse.
-newRange:
- for {
- r := getInUseRange(s.scavAddr)
- if r.size() == 0 {
- break
- }
- unlockHeap()
-
- // Iterate over all of the chunks described by r.
- // Note that r.limit is the exclusive upper bound, but what
- // we want is the top chunk instead, inclusive, so subtract 1.
- bot, top := chunkIndex(r.base), chunkIndex(r.limit-1)
- for i := top; i >= bot; i-- {
+ // The heap need not be locked.
+ findCandidate := func(work addrRange) (chunkIdx, bool) {
+ // Iterate over this work's chunks.
+ for i := chunkIndex(work.limit.addr() - 1); i >= chunkIndex(work.base.addr()); i-- {
// If this chunk is totally in-use or has no unscavenged pages, don't bother
- // doing a more sophisticated check.
+ // doing a more sophisticated check.
//
// Note we're accessing the summary and the chunks without a lock, but
// that's fine. We're being optimistic anyway.
@@ -570,70 +642,77 @@ newRange:
// see a nil pointer in this case if we do race with heap growth, but
// just defensively ignore the nils. This operation is optimistic anyway.
l2 := (*[1 << pallocChunksL2Bits]pallocData)(atomic.Loadp(unsafe.Pointer(&s.chunks[i.l1()])))
- if l2 == nil || !l2[i.l2()].hasScavengeCandidate(minPages) {
- continue
+ if l2 != nil && l2[i.l2()].hasScavengeCandidate(minPages) {
+ return i, true
}
+ }
+ return 0, false
+ }
- // We found a candidate, so let's lock and verify it.
- lockHeap()
-
- // Find, verify, and scavenge if we can.
- chunk := s.chunkOf(i)
- base, npages := chunk.findScavengeCandidate(pallocChunkPages-1, minPages, maxPages)
- if npages > 0 {
- // We found memory to scavenge! Mark the bits and report that up.
- // scavengeRangeLocked will update scavAddr for us, also.
- s.scavengeRangeLocked(i, base, npages)
- unlockHeap()
- return uintptr(npages) * pageSize
- }
+ // Slow path: iterate optimistically over the in-use address space
+ // looking for any free and unscavenged page. If we think we see something,
+ // lock and verify it!
+ for work.size() != 0 {
+ unlockHeap()
- // We were fooled, let's take this opportunity to move the scavAddr
- // all the way down to where we searched as scavenged for future calls
- // and keep iterating. Then, go get a new range.
- s.scavAddr = chunkBase(i-1) + pallocChunkPages*pageSize - 1
- continue newRange
- }
+ // Search for the candidate.
+ candidateChunkIdx, ok := findCandidate(work)
+
+ // Lock the heap. We need to do this now if we found a candidate or not.
+ // If we did, we'll verify it. If not, we need to lock before returning
+ // anyway.
lockHeap()
- // Move the scavenger down the heap, past everything we just searched.
- // Since we don't check if scavAddr moved while twe let go of the heap lock,
- // it's possible that it moved down and we're moving it up here. This
- // raciness could result in us searching parts of the heap unnecessarily.
- // TODO(mknyszek): Remove this racy behavior through explicit address
- // space reservations, which are difficult to do with just scavAddr.
- s.scavAddr = r.base - 1
- }
- // We reached the end of the in-use address space and couldn't find anything,
- // so signal that there's nothing left to scavenge.
- s.scavAddr = minScavAddr
- unlockHeap()
+ if !ok {
+ // We didn't find a candidate, so we're done.
+ work.limit = work.base
+ break
+ }
+
+ // Find, verify, and scavenge if we can.
+ chunk := s.chunkOf(candidateChunkIdx)
+ base, npages := chunk.findScavengeCandidate(pallocChunkPages-1, minPages, maxPages)
+ if npages > 0 {
+ work.limit = offAddr{s.scavengeRangeLocked(candidateChunkIdx, base, npages)}
+ return uintptr(npages) * pageSize, work
+ }
- return 0
+ // We were fooled, so let's continue from where we left off.
+ work.limit = offAddr{chunkBase(candidateChunkIdx)}
+ }
+ return 0, work
}
// scavengeRangeLocked scavenges the given region of memory.
+// The region of memory is described by its chunk index (ci),
+// the starting page index of the region relative to that
+// chunk (base), and the length of the region in pages (npages).
+//
+// Returns the base address of the scavenged region.
//
// s.mheapLock must be held.
-func (s *pageAlloc) scavengeRangeLocked(ci chunkIdx, base, npages uint) {
+func (s *pageAlloc) scavengeRangeLocked(ci chunkIdx, base, npages uint) uintptr {
s.chunkOf(ci).scavenged.setRange(base, npages)
// Compute the full address for the start of the range.
addr := chunkBase(ci) + uintptr(base)*pageSize
- // Update the scav pointer.
- s.scavAddr = addr - 1
+ // Update the scavenge low watermark.
+ if oAddr := (offAddr{addr}); oAddr.lessThan(s.scav.scavLWM) {
+ s.scav.scavLWM = oAddr
+ }
// Only perform the actual scavenging if we're not in a test.
// It's dangerous to do so otherwise.
if s.test {
- return
+ return addr
}
sysUnused(unsafe.Pointer(addr), uintptr(npages)*pageSize)
// Update global accounting only when not in test, otherwise
// the runtime's accounting will be wrong.
mSysStatInc(&memstats.heap_released, uintptr(npages)*pageSize)
+ return addr
}
// fillAligned returns x but with all zeroes in m-aligned
diff --git a/src/runtime/mgcscavenge_test.go b/src/runtime/mgcscavenge_test.go
index 58f9e3a80d..7f619b1e7d 100644
--- a/src/runtime/mgcscavenge_test.go
+++ b/src/runtime/mgcscavenge_test.go
@@ -419,12 +419,12 @@ func TestPageAllocScavenge(t *testing.T) {
}
for name, v := range tests {
v := v
- runTest := func(t *testing.T, locked bool) {
+ runTest := func(t *testing.T, mayUnlock bool) {
b := NewPageAlloc(v.beforeAlloc, v.beforeScav)
defer FreePageAlloc(b)
for iter, h := range v.expect {
- if got := b.Scavenge(h.request, locked); got != h.expect {
+ if got := b.Scavenge(h.request, mayUnlock); got != h.expect {
t.Fatalf("bad scavenge #%d: want %d, got %d", iter+1, h.expect, got)
}
}
@@ -436,7 +436,7 @@ func TestPageAllocScavenge(t *testing.T) {
t.Run(name, func(t *testing.T) {
runTest(t, false)
})
- t.Run(name+"Locked", func(t *testing.T) {
+ t.Run(name+"MayUnlock", func(t *testing.T) {
runTest(t, true)
})
}
diff --git a/src/runtime/mgcsweep.go b/src/runtime/mgcsweep.go
index 2f3bf1d1e9..3aa3afc028 100644
--- a/src/runtime/mgcsweep.go
+++ b/src/runtime/mgcsweep.go
@@ -246,8 +246,8 @@ func sweepone() uintptr {
// Decrement the number of active sweepers and if this is the
// last one print trace information.
if atomic.Xadd(&mheap_.sweepers, -1) == 0 && atomic.Load(&mheap_.sweepdone) != 0 {
- // Since the sweeper is done, reset the scavenger's pointer
- // into the heap and wake it if necessary.
+ // Since the sweeper is done, move the scavenge gen forward (signalling
+ // that there's new work to do) and wake the scavenger.
//
// The scavenger is signaled by the last sweeper because once
// sweeping is done, we will definitely have useful work for
@@ -259,7 +259,7 @@ func sweepone() uintptr {
// with scavenging work.
systemstack(func() {
lock(&mheap_.lock)
- mheap_.pages.resetScavengeAddr()
+ mheap_.pages.scavengeStartGen()
unlock(&mheap_.lock)
})
// Since we might sweep in an allocation path, it's not possible
@@ -439,10 +439,31 @@ func (s *mspan) sweep(preserve bool) bool {
}
}
+ // Check for zombie objects.
+ if s.freeindex < s.nelems {
+ // Everything < freeindex is allocated and hence
+ // cannot be zombies.
+ //
+ // Check the first bitmap byte, where we have to be
+ // careful with freeindex.
+ obj := s.freeindex
+ if (*s.gcmarkBits.bytep(obj / 8)&^*s.allocBits.bytep(obj / 8))>>(obj%8) != 0 {
+ s.reportZombies()
+ }
+ // Check remaining bytes.
+ for i := obj/8 + 1; i < divRoundUp(s.nelems, 8); i++ {
+ if *s.gcmarkBits.bytep(i)&^*s.allocBits.bytep(i) != 0 {
+ s.reportZombies()
+ }
+ }
+ }
+
// Count the number of free objects in this span.
nalloc := uint16(s.countAlloc())
nfreed := s.allocCount - nalloc
if nalloc > s.allocCount {
+ // The zombie check above should have caught this in
+ // more detail.
print("runtime: nelems=", s.nelems, " nalloc=", nalloc, " previous allocCount=", s.allocCount, " nfreed=", nfreed, "\n")
throw("sweep increased allocation count")
}
@@ -755,6 +776,57 @@ func (s *mspan) oldSweep(preserve bool) bool {
return res
}
+// reportZombies reports any marked but free objects in s and throws.
+//
+// This generally means one of the following:
+//
+// 1. User code converted a pointer to a uintptr and then back
+// unsafely, and a GC ran while the uintptr was the only reference to
+// an object.
+//
+// 2. User code (or a compiler bug) constructed a bad pointer that
+// points to a free slot, often a past-the-end pointer.
+//
+// 3. The GC two cycles ago missed a pointer and freed a live object,
+// but it was still live in the last cycle, so this GC cycle found a
+// pointer to that object and marked it.
+func (s *mspan) reportZombies() {
+ printlock()
+ print("runtime: marked free object in span ", s, ", elemsize=", s.elemsize, " freeindex=", s.freeindex, " (bad use of unsafe.Pointer? try -d=checkptr)\n")
+ mbits := s.markBitsForBase()
+ abits := s.allocBitsForIndex(0)
+ for i := uintptr(0); i < s.nelems; i++ {
+ addr := s.base() + i*s.elemsize
+ print(hex(addr))
+ alloc := i < s.freeindex || abits.isMarked()
+ if alloc {
+ print(" alloc")
+ } else {
+ print(" free ")
+ }
+ if mbits.isMarked() {
+ print(" marked ")
+ } else {
+ print(" unmarked")
+ }
+ zombie := mbits.isMarked() && !alloc
+ if zombie {
+ print(" zombie")
+ }
+ print("\n")
+ if zombie {
+ length := s.elemsize
+ if length > 1024 {
+ length = 1024
+ }
+ hexdumpWords(addr, addr+length, nil)
+ }
+ mbits.advance()
+ abits.advance()
+ }
+ throw("found pointer to free object")
+}
+
// deductSweepCredit deducts sweep credit for allocating a span of
// size spanBytes. This must be performed *before* the span is
// allocated to ensure the system has enough credit. If necessary, it
diff --git a/src/runtime/mheap.go b/src/runtime/mheap.go
index b7c5add40c..2c7bfd8a59 100644
--- a/src/runtime/mheap.go
+++ b/src/runtime/mheap.go
@@ -98,7 +98,7 @@ type mheap struct {
// For !go115NewMCentralImpl.
sweepSpans [2]gcSweepBuf
- // _ uint32 // align uint64 fields on 32-bit for atomics
+ _ uint32 // align uint64 fields on 32-bit for atomics
// Proportional sweep
//
@@ -576,13 +576,13 @@ func (sc spanClass) noscan() bool {
//
//go:nosplit
func arenaIndex(p uintptr) arenaIdx {
- return arenaIdx((p + arenaBaseOffset) / heapArenaBytes)
+ return arenaIdx((p - arenaBaseOffset) / heapArenaBytes)
}
// arenaBase returns the low address of the region covered by heap
// arena i.
func arenaBase(i arenaIdx) uintptr {
- return uintptr(i)*heapArenaBytes - arenaBaseOffset
+ return uintptr(i)*heapArenaBytes + arenaBaseOffset
}
type arenaIdx uint
@@ -1283,9 +1283,10 @@ HaveSpan:
// Publish the span in various locations.
// This is safe to call without the lock held because the slots
- // related to this span will only every be read or modified by
- // this thread until pointers into the span are published or
- // pageInUse is updated.
+ // related to this span will only ever be read or modified by
+ // this thread until pointers into the span are published (and
+ // we execute a publication barrier at the end of this function
+ // before that happens) or pageInUse is updated.
h.setSpans(s.base(), npages, s)
if !manual {
@@ -1315,6 +1316,11 @@ HaveSpan:
traceHeapAlloc()
}
}
+
+ // Make sure the newly allocated span will be observed
+ // by the GC before pointers into the span are published.
+ publicationBarrier()
+
return s
}
@@ -1327,8 +1333,11 @@ func (h *mheap) grow(npage uintptr) bool {
ask := alignUp(npage, pallocChunkPages) * pageSize
totalGrowth := uintptr(0)
- nBase := alignUp(h.curArena.base+ask, physPageSize)
- if nBase > h.curArena.end {
+ // This may overflow because ask could be very large
+ // and is otherwise unrelated to h.curArena.base.
+ end := h.curArena.base + ask
+ nBase := alignUp(end, physPageSize)
+ if nBase > h.curArena.end || /* overflow */ end < h.curArena.base {
// Not enough room in the current arena. Allocate more
// arena space. This may not be contiguous with the
// current arena, so we have to request the full ask.
@@ -1364,7 +1373,10 @@ func (h *mheap) grow(npage uintptr) bool {
mSysStatInc(&memstats.heap_released, asize)
mSysStatInc(&memstats.heap_idle, asize)
- // Recalculate nBase
+ // Recalculate nBase.
+ // We know this won't overflow, because sysAlloc returned
+ // a valid region starting at h.curArena.base which is at
+ // least ask bytes in size.
nBase = alignUp(h.curArena.base+ask, physPageSize)
}
@@ -1383,7 +1395,7 @@ func (h *mheap) grow(npage uintptr) bool {
if overage := uintptr(retained + uint64(totalGrowth) - h.scavengeGoal); todo > overage {
todo = overage
}
- h.pages.scavenge(todo, true)
+ h.pages.scavenge(todo, false)
}
return true
}
@@ -1467,9 +1479,9 @@ func (h *mheap) freeSpanLocked(s *mspan, acctinuse, acctidle bool) {
h.freeMSpanLocked(s)
}
-// scavengeAll visits each node in the free treap and scavenges the
-// treapNode's span. It then removes the scavenged span from
-// unscav and adds it into scav before continuing.
+// scavengeAll acquires the heap lock (blocking any additional
+// manipulation of the page allocator) and iterates over the whole
+// heap, scavenging every free page available.
func (h *mheap) scavengeAll() {
// Disallow malloc or panic while holding the heap lock. We do
// this here because this is a non-mallocgc entry-point to
@@ -1477,14 +1489,16 @@ func (h *mheap) scavengeAll() {
gp := getg()
gp.m.mallocing++
lock(&h.lock)
- // Reset the scavenger address so we have access to the whole heap.
- h.pages.resetScavengeAddr()
- released := h.pages.scavenge(^uintptr(0), true)
+ // Start a new scavenge generation so we have a chance to walk
+ // over the whole heap.
+ h.pages.scavengeStartGen()
+ released := h.pages.scavenge(^uintptr(0), false)
+ gen := h.pages.scav.gen
unlock(&h.lock)
gp.m.mallocing--
if debug.scavtrace > 0 {
- printScavTrace(released, true)
+ printScavTrace(gen, released, true)
}
}
diff --git a/src/runtime/mpagealloc.go b/src/runtime/mpagealloc.go
index 60926fbebf..60f7f9ff58 100644
--- a/src/runtime/mpagealloc.go
+++ b/src/runtime/mpagealloc.go
@@ -81,20 +81,14 @@ const (
// there should this change.
pallocChunksL2Bits = heapAddrBits - logPallocChunkBytes - pallocChunksL1Bits
pallocChunksL1Shift = pallocChunksL2Bits
-
- // Maximum searchAddr value, which indicates that the heap has no free space.
- //
- // We subtract arenaBaseOffset because we want this to represent the maximum
- // value in the shifted address space, but searchAddr is stored as a regular
- // memory address. See arenaBaseOffset for details.
- maxSearchAddr = ^uintptr(0) - arenaBaseOffset
-
- // Minimum scavAddr value, which indicates that the scavenger is done.
- //
- // minScavAddr + arenaBaseOffset == 0
- minScavAddr = (^arenaBaseOffset + 1) & uintptrMask
)
+// Maximum searchAddr value, which indicates that the heap has no free space.
+//
+// We alias maxOffAddr just to make it clear that this is the maximum address
+// for the page allocator's search space. See maxOffAddr for details.
+var maxSearchAddr = maxOffAddr
+
// Global chunk index.
//
// Represents an index into the leaf level of the radix tree.
@@ -105,12 +99,12 @@ type chunkIdx uint
// chunkIndex returns the global index of the palloc chunk containing the
// pointer p.
func chunkIndex(p uintptr) chunkIdx {
- return chunkIdx((p + arenaBaseOffset) / pallocChunkBytes)
+ return chunkIdx((p - arenaBaseOffset) / pallocChunkBytes)
}
// chunkIndex returns the base address of the palloc chunk at index ci.
func chunkBase(ci chunkIdx) uintptr {
- return uintptr(ci)*pallocChunkBytes - arenaBaseOffset
+ return uintptr(ci)*pallocChunkBytes + arenaBaseOffset
}
// chunkPageIndex computes the index of the page that contains p,
@@ -139,6 +133,18 @@ func (i chunkIdx) l2() uint {
}
}
+// offAddrToLevelIndex converts an address in the offset address space
+// to the index into summary[level] containing addr.
+func offAddrToLevelIndex(level int, addr offAddr) int {
+ return int((addr.a - arenaBaseOffset) >> levelShift[level])
+}
+
+// levelIndexToOffAddr converts an index into summary[level] into
+// the corresponding address in the offset address space.
+func levelIndexToOffAddr(level, idx int) offAddr {
+ return offAddr{(uintptr(idx) << levelShift[level]) + arenaBaseOffset}
+}
+
// addrsToSummaryRange converts base and limit pointers into a range
// of entries for the given summary level.
//
@@ -153,8 +159,8 @@ func addrsToSummaryRange(level int, base, limit uintptr) (lo int, hi int) {
// of a summary's max page count boundary for this level
// (1 << levelLogPages[level]). So, make limit an inclusive upper bound
// then shift, then add 1, so we get an exclusive upper bound at the end.
- lo = int((base + arenaBaseOffset) >> levelShift[level])
- hi = int(((limit-1)+arenaBaseOffset)>>levelShift[level]) + 1
+ lo = int((base - arenaBaseOffset) >> levelShift[level])
+ hi = int(((limit-1)-arenaBaseOffset)>>levelShift[level]) + 1
return
}
@@ -237,16 +243,7 @@ type pageAlloc struct {
// Note that adding in arenaBaseOffset transforms addresses
// to a new address space with a linear view of the full address
// space on architectures with segmented address spaces.
- searchAddr uintptr
-
- // The address to start a scavenge candidate search with. It
- // need not point to memory contained in inUse.
- scavAddr uintptr
-
- // The amount of memory scavenged since the last scavtrace print.
- //
- // Read and updated atomically.
- scavReleased uintptr
+ searchAddr offAddr
// start and end represent the chunk indices
// which pageAlloc knows about. It assumes
@@ -267,6 +264,33 @@ type pageAlloc struct {
// All access is protected by the mheapLock.
inUse addrRanges
+ // scav stores the scavenger state.
+ //
+ // All fields are protected by mheapLock.
+ scav struct {
+ // inUse is a slice of ranges of address space which have not
+ // yet been looked at by the scavenger.
+ inUse addrRanges
+
+ // gen is the scavenge generation number.
+ gen uint32
+
+ // reservationBytes is how large of a reservation should be made
+ // in bytes of address space for each scavenge iteration.
+ reservationBytes uintptr
+
+ // released is the amount of memory released this generation.
+ released uintptr
+
+ // scavLWM is the lowest (offset) address that the scavenger reached this
+ // scavenge generation.
+ scavLWM offAddr
+
+ // freeHWM is the highest (offset) address of a page that was freed to
+ // the page allocator this scavenge generation.
+ freeHWM offAddr
+ }
+
// mheap_.lock. This level of indirection makes it possible
// to test pageAlloc indepedently of the runtime allocator.
mheapLock *mutex
@@ -299,34 +323,11 @@ func (s *pageAlloc) init(mheapLock *mutex, sysStat *uint64) {
// Start with the searchAddr in a state indicating there's no free memory.
s.searchAddr = maxSearchAddr
- // Start with the scavAddr in a state indicating there's nothing more to do.
- s.scavAddr = minScavAddr
-
// Set the mheapLock.
s.mheapLock = mheapLock
-}
-// compareSearchAddrTo compares an address against s.searchAddr in a linearized
-// view of the address space on systems with discontinuous process address spaces.
-// This linearized view is the same one generated by chunkIndex and arenaIndex,
-// done by adding arenaBaseOffset.
-//
-// On systems without a discontinuous address space, it's just a normal comparison.
-//
-// Returns < 0 if addr is less than s.searchAddr in the linearized address space.
-// Returns > 0 if addr is greater than s.searchAddr in the linearized address space.
-// Returns 0 if addr and s.searchAddr are equal.
-func (s *pageAlloc) compareSearchAddrTo(addr uintptr) int {
- // Compare with arenaBaseOffset added because it gives us a linear, contiguous view
- // of the heap on architectures with signed address spaces.
- lAddr := addr + arenaBaseOffset
- lSearchAddr := s.searchAddr + arenaBaseOffset
- if lAddr < lSearchAddr {
- return -1
- } else if lAddr > lSearchAddr {
- return 1
- }
- return 0
+ // Initialize scavenge tracking state.
+ s.scav.scavLWM = maxSearchAddr
}
// chunkOf returns the chunk at the given chunk index.
@@ -362,13 +363,13 @@ func (s *pageAlloc) grow(base, size uintptr) {
// Note that [base, limit) will never overlap with any existing
// range inUse because grow only ever adds never-used memory
// regions to the page allocator.
- s.inUse.add(addrRange{base, limit})
+ s.inUse.add(makeAddrRange(base, limit))
// A grow operation is a lot like a free operation, so if our
- // chunk ends up below the (linearized) s.searchAddr, update
- // s.searchAddr to the new address, just like in free.
- if s.compareSearchAddrTo(base) < 0 {
- s.searchAddr = base
+ // chunk ends up below s.searchAddr, update s.searchAddr to the
+ // new address, just like in free.
+ if b := (offAddr{base}); b.lessThan(s.searchAddr) {
+ s.searchAddr = b
}
// Add entries into chunks, which is sparse, if needed. Then,
@@ -532,7 +533,7 @@ func (s *pageAlloc) allocRange(base, npages uintptr) uintptr {
// searchAddr returned is invalid and must be ignored.
//
// s.mheapLock must be held.
-func (s *pageAlloc) find(npages uintptr) (uintptr, uintptr) {
+func (s *pageAlloc) find(npages uintptr) (uintptr, offAddr) {
// Search algorithm.
//
// This algorithm walks each level l of the radix tree from the root level
@@ -572,13 +573,13 @@ func (s *pageAlloc) find(npages uintptr) (uintptr, uintptr) {
// firstFree is updated by calling foundFree each time free space in the
// heap is discovered.
//
- // At the end of the search, base-arenaBaseOffset is the best new
+ // At the end of the search, base.addr() is the best new
// searchAddr we could deduce in this search.
firstFree := struct {
- base, bound uintptr
+ base, bound offAddr
}{
- base: 0,
- bound: (1<<heapAddrBits - 1),
+ base: minOffAddr,
+ bound: maxOffAddr,
}
// foundFree takes the given address range [addr, addr+size) and
// updates firstFree if it is a narrower range. The input range must
@@ -589,17 +590,17 @@ func (s *pageAlloc) find(npages uintptr) (uintptr, uintptr) {
// pages on the root level and narrow that down if we descend into
// that summary. But as soon as we need to iterate beyond that summary
// in a level to find a large enough range, we'll stop narrowing.
- foundFree := func(addr, size uintptr) {
- if firstFree.base <= addr && addr+size-1 <= firstFree.bound {
+ foundFree := func(addr offAddr, size uintptr) {
+ if firstFree.base.lessEqual(addr) && addr.add(size-1).lessEqual(firstFree.bound) {
// This range fits within the current firstFree window, so narrow
// down the firstFree window to the base and bound of this range.
firstFree.base = addr
- firstFree.bound = addr + size - 1
- } else if !(addr+size-1 < firstFree.base || addr > firstFree.bound) {
+ firstFree.bound = addr.add(size - 1)
+ } else if !(addr.add(size-1).lessThan(firstFree.base) || firstFree.bound.lessThan(addr)) {
// This range only partially overlaps with the firstFree range,
// so throw.
- print("runtime: addr = ", hex(addr), ", size = ", size, "\n")
- print("runtime: base = ", hex(firstFree.base), ", bound = ", hex(firstFree.bound), "\n")
+ print("runtime: addr = ", hex(addr.addr()), ", size = ", size, "\n")
+ print("runtime: base = ", hex(firstFree.base.addr()), ", bound = ", hex(firstFree.bound.addr()), "\n")
throw("range partially overlaps")
}
}
@@ -629,7 +630,7 @@ nextLevel:
// searchAddr on the previous level or we're on the root leve, in which
// case the searchAddr should be the same as i after levelShift.
j0 := 0
- if searchIdx := int((s.searchAddr + arenaBaseOffset) >> levelShift[l]); searchIdx&^(entriesPerBlock-1) == i {
+ if searchIdx := offAddrToLevelIndex(l, s.searchAddr); searchIdx&^(entriesPerBlock-1) == i {
j0 = searchIdx & (entriesPerBlock - 1)
}
@@ -655,7 +656,7 @@ nextLevel:
// We've encountered a non-zero summary which means
// free memory, so update firstFree.
- foundFree(uintptr((i+j)<<levelShift[l]), (uintptr(1)<<logMaxPages)*pageSize)
+ foundFree(levelIndexToOffAddr(l, i+j), (uintptr(1)<<logMaxPages)*pageSize)
s := sum.start()
if size+s >= uint(npages) {
@@ -693,8 +694,8 @@ nextLevel:
if size >= uint(npages) {
// We found a sufficiently large run of free pages straddling
// some boundary, so compute the address and return it.
- addr := uintptr(i<<levelShift[l]) - arenaBaseOffset + uintptr(base)*pageSize
- return addr, firstFree.base - arenaBaseOffset
+ addr := levelIndexToOffAddr(l, i).add(uintptr(base) * pageSize).addr()
+ return addr, firstFree.base
}
if l == 0 {
// We're at level zero, so that means we've exhausted our search.
@@ -706,7 +707,7 @@ nextLevel:
// lied to us. In either case, dump some useful state and throw.
print("runtime: summary[", l-1, "][", lastSumIdx, "] = ", lastSum.start(), ", ", lastSum.max(), ", ", lastSum.end(), "\n")
print("runtime: level = ", l, ", npages = ", npages, ", j0 = ", j0, "\n")
- print("runtime: s.searchAddr = ", hex(s.searchAddr), ", i = ", i, "\n")
+ print("runtime: s.searchAddr = ", hex(s.searchAddr.addr()), ", i = ", i, "\n")
print("runtime: levelShift[level] = ", levelShift[l], ", levelBits[level] = ", levelBits[l], "\n")
for j := 0; j < len(entries); j++ {
sum := entries[j]
@@ -739,8 +740,8 @@ nextLevel:
// Since we actually searched the chunk, we may have
// found an even narrower free window.
searchAddr := chunkBase(ci) + uintptr(searchIdx)*pageSize
- foundFree(searchAddr+arenaBaseOffset, chunkBase(ci+1)-searchAddr)
- return addr, firstFree.base - arenaBaseOffset
+ foundFree(offAddr{searchAddr}, chunkBase(ci+1)-searchAddr)
+ return addr, firstFree.base
}
// alloc allocates npages worth of memory from the page heap, returning the base
@@ -754,25 +755,25 @@ nextLevel:
func (s *pageAlloc) alloc(npages uintptr) (addr uintptr, scav uintptr) {
// If the searchAddr refers to a region which has a higher address than
// any known chunk, then we know we're out of memory.
- if chunkIndex(s.searchAddr) >= s.end {
+ if chunkIndex(s.searchAddr.addr()) >= s.end {
return 0, 0
}
// If npages has a chance of fitting in the chunk where the searchAddr is,
// search it directly.
- searchAddr := uintptr(0)
- if pallocChunkPages-chunkPageIndex(s.searchAddr) >= uint(npages) {
+ searchAddr := minOffAddr
+ if pallocChunkPages-chunkPageIndex(s.searchAddr.addr()) >= uint(npages) {
// npages is guaranteed to be no greater than pallocChunkPages here.
- i := chunkIndex(s.searchAddr)
+ i := chunkIndex(s.searchAddr.addr())
if max := s.summary[len(s.summary)-1][i].max(); max >= uint(npages) {
- j, searchIdx := s.chunkOf(i).find(npages, chunkPageIndex(s.searchAddr))
+ j, searchIdx := s.chunkOf(i).find(npages, chunkPageIndex(s.searchAddr.addr()))
if j == ^uint(0) {
print("runtime: max = ", max, ", npages = ", npages, "\n")
- print("runtime: searchIdx = ", chunkPageIndex(s.searchAddr), ", s.searchAddr = ", hex(s.searchAddr), "\n")
+ print("runtime: searchIdx = ", chunkPageIndex(s.searchAddr.addr()), ", s.searchAddr = ", hex(s.searchAddr.addr()), "\n")
throw("bad summary data")
}
addr = chunkBase(i) + uintptr(j)*pageSize
- searchAddr = chunkBase(i) + uintptr(searchIdx)*pageSize
+ searchAddr = offAddr{chunkBase(i) + uintptr(searchIdx)*pageSize}
goto Found
}
}
@@ -794,10 +795,10 @@ Found:
// Go ahead and actually mark the bits now that we have an address.
scav = s.allocRange(addr, npages)
- // If we found a higher (linearized) searchAddr, we know that all the
- // heap memory before that searchAddr in a linear address space is
+ // If we found a higher searchAddr, we know that all the
+ // heap memory before that searchAddr in an offset address space is
// allocated, so bump s.searchAddr up to the new one.
- if s.compareSearchAddrTo(searchAddr) > 0 {
+ if s.searchAddr.lessThan(searchAddr) {
s.searchAddr = searchAddr
}
return addr, scav
@@ -807,9 +808,14 @@ Found:
//
// s.mheapLock must be held.
func (s *pageAlloc) free(base, npages uintptr) {
- // If we're freeing pages below the (linearized) s.searchAddr, update searchAddr.
- if s.compareSearchAddrTo(base) < 0 {
- s.searchAddr = base
+ // If we're freeing pages below the s.searchAddr, update searchAddr.
+ if b := (offAddr{base}); b.lessThan(s.searchAddr) {
+ s.searchAddr = b
+ }
+ // Update the free high watermark for the scavenger.
+ limit := base + npages*pageSize - 1
+ if offLimit := (offAddr{limit}); s.scav.freeHWM.lessThan(offLimit) {
+ s.scav.freeHWM = offLimit
}
if npages == 1 {
// Fast path: we're clearing a single bit, and we know exactly
@@ -818,7 +824,6 @@ func (s *pageAlloc) free(base, npages uintptr) {
s.chunkOf(i).free1(chunkPageIndex(base))
} else {
// Slow path: we're clearing more bits so we may need to iterate.
- limit := base + npages*pageSize - 1
sc, ec := chunkIndex(base), chunkIndex(limit)
si, ei := chunkPageIndex(base), chunkPageIndex(limit)
diff --git a/src/runtime/mpagealloc_64bit.go b/src/runtime/mpagealloc_64bit.go
index 0b475ed206..831626e4b2 100644
--- a/src/runtime/mpagealloc_64bit.go
+++ b/src/runtime/mpagealloc_64bit.go
@@ -106,7 +106,7 @@ func (s *pageAlloc) sysGrow(base, limit uintptr) {
// of summary indices which must be mapped to support those addresses
// in the summary range.
addrRangeToSummaryRange := func(level int, r addrRange) (int, int) {
- sumIdxBase, sumIdxLimit := addrsToSummaryRange(level, r.base, r.limit)
+ sumIdxBase, sumIdxLimit := addrsToSummaryRange(level, r.base.addr(), r.limit.addr())
return blockAlignSummaryRange(level, sumIdxBase, sumIdxLimit)
}
@@ -118,8 +118,8 @@ func (s *pageAlloc) sysGrow(base, limit uintptr) {
limitOffset := alignUp(uintptr(sumIdxLimit)*pallocSumBytes, physPageSize)
base := unsafe.Pointer(&s.summary[level][0])
return addrRange{
- uintptr(add(base, baseOffset)),
- uintptr(add(base, limitOffset)),
+ offAddr{uintptr(add(base, baseOffset))},
+ offAddr{uintptr(add(base, limitOffset))},
}
}
@@ -145,7 +145,7 @@ func (s *pageAlloc) sysGrow(base, limit uintptr) {
// Walk up the radix tree and map summaries in as needed.
for l := range s.summary {
// Figure out what part of the summary array this new address space needs.
- needIdxBase, needIdxLimit := addrRangeToSummaryRange(l, addrRange{base, limit})
+ needIdxBase, needIdxLimit := addrRangeToSummaryRange(l, makeAddrRange(base, limit))
// Update the summary slices with a new upper-bound. This ensures
// we get tight bounds checks on at least the top bound.
@@ -174,7 +174,7 @@ func (s *pageAlloc) sysGrow(base, limit uintptr) {
}
// Map and commit need.
- sysMap(unsafe.Pointer(need.base), need.size(), s.sysStat)
- sysUsed(unsafe.Pointer(need.base), need.size())
+ sysMap(unsafe.Pointer(need.base.addr()), need.size(), s.sysStat)
+ sysUsed(unsafe.Pointer(need.base.addr()), need.size())
}
}
diff --git a/src/runtime/mpagecache.go b/src/runtime/mpagecache.go
index fae54d7cdd..683a997136 100644
--- a/src/runtime/mpagecache.go
+++ b/src/runtime/mpagecache.go
@@ -91,8 +91,8 @@ func (c *pageCache) flush(s *pageAlloc) {
}
// Since this is a lot like a free, we need to make sure
// we update the searchAddr just like free does.
- if s.compareSearchAddrTo(c.base) < 0 {
- s.searchAddr = c.base
+ if b := (offAddr{c.base}); b.lessThan(s.searchAddr) {
+ s.searchAddr = b
}
s.update(c.base, pageCachePages, false, false)
*c = pageCache{}
@@ -106,15 +106,15 @@ func (c *pageCache) flush(s *pageAlloc) {
func (s *pageAlloc) allocToCache() pageCache {
// If the searchAddr refers to a region which has a higher address than
// any known chunk, then we know we're out of memory.
- if chunkIndex(s.searchAddr) >= s.end {
+ if chunkIndex(s.searchAddr.addr()) >= s.end {
return pageCache{}
}
c := pageCache{}
- ci := chunkIndex(s.searchAddr) // chunk index
+ ci := chunkIndex(s.searchAddr.addr()) // chunk index
if s.summary[len(s.summary)-1][ci] != 0 {
// Fast path: there's free pages at or near the searchAddr address.
chunk := s.chunkOf(ci)
- j, _ := chunk.find(1, chunkPageIndex(s.searchAddr))
+ j, _ := chunk.find(1, chunkPageIndex(s.searchAddr.addr()))
if j == ^uint(0) {
throw("bad summary data")
}
@@ -156,6 +156,6 @@ func (s *pageAlloc) allocToCache() pageCache {
// However, s.searchAddr is not allowed to point into unmapped heap memory
// unless it is maxSearchAddr, so make it the last page as opposed to
// the page after.
- s.searchAddr = c.base + pageSize*(pageCachePages-1)
+ s.searchAddr = offAddr{c.base + pageSize*(pageCachePages-1)}
return c
}
diff --git a/src/runtime/mranges.go b/src/runtime/mranges.go
index b13385165b..e23d0778eb 100644
--- a/src/runtime/mranges.go
+++ b/src/runtime/mranges.go
@@ -15,23 +15,41 @@ import (
)
// addrRange represents a region of address space.
+//
+// An addrRange must never span a gap in the address space.
type addrRange struct {
// base and limit together represent the region of address space
// [base, limit). That is, base is inclusive, limit is exclusive.
- base, limit uintptr
+ // These are address over an offset view of the address space on
+ // platforms with a segmented address space, that is, on platforms
+ // where arenaBaseOffset != 0.
+ base, limit offAddr
+}
+
+// makeAddrRange creates a new address range from two virtual addresses.
+//
+// Throws if the base and limit are not in the same memory segment.
+func makeAddrRange(base, limit uintptr) addrRange {
+ r := addrRange{offAddr{base}, offAddr{limit}}
+ if (base-arenaBaseOffset >= base) != (limit-arenaBaseOffset >= limit) {
+ throw("addr range base and limit are not in the same memory segment")
+ }
+ return r
}
// size returns the size of the range represented in bytes.
func (a addrRange) size() uintptr {
- if a.limit <= a.base {
+ if !a.base.lessThan(a.limit) {
return 0
}
- return a.limit - a.base
+ // Subtraction is safe because limit and base must be in the same
+ // segment of the address space.
+ return a.limit.diff(a.base)
}
// contains returns whether or not the range contains a given address.
func (a addrRange) contains(addr uintptr) bool {
- return addr >= a.base && addr < a.limit
+ return a.base.lessEqual(offAddr{addr}) && (offAddr{addr}).lessThan(a.limit)
}
// subtract takes the addrRange toPrune and cuts out any overlap with
@@ -39,18 +57,90 @@ func (a addrRange) contains(addr uintptr) bool {
// either don't overlap at all, only overlap on one side, or are equal.
// If b is strictly contained in a, thus forcing a split, it will throw.
func (a addrRange) subtract(b addrRange) addrRange {
- if a.base >= b.base && a.limit <= b.limit {
+ if b.base.lessEqual(a.base) && a.limit.lessEqual(b.limit) {
return addrRange{}
- } else if a.base < b.base && a.limit > b.limit {
+ } else if a.base.lessThan(b.base) && b.limit.lessThan(a.limit) {
throw("bad prune")
- } else if a.limit > b.limit && a.base < b.limit {
+ } else if b.limit.lessThan(a.limit) && a.base.lessThan(b.limit) {
a.base = b.limit
- } else if a.base < b.base && a.limit > b.base {
+ } else if a.base.lessThan(b.base) && b.base.lessThan(a.limit) {
a.limit = b.base
}
return a
}
+// removeGreaterEqual removes all addresses in a greater than or equal
+// to addr and returns the new range.
+func (a addrRange) removeGreaterEqual(addr uintptr) addrRange {
+ if (offAddr{addr}).lessEqual(a.base) {
+ return addrRange{}
+ }
+ if a.limit.lessEqual(offAddr{addr}) {
+ return a
+ }
+ return makeAddrRange(a.base.addr(), addr)
+}
+
+var (
+ // minOffAddr is the minimum address in the offset space, and
+ // it corresponds to the virtual address arenaBaseOffset.
+ minOffAddr = offAddr{arenaBaseOffset}
+
+ // maxOffAddr is the maximum address in the offset address
+ // space. It corresponds to the highest virtual address representable
+ // by the page alloc chunk and heap arena maps.
+ maxOffAddr = offAddr{(((1 << heapAddrBits) - 1) + arenaBaseOffset) & uintptrMask}
+)
+
+// offAddr represents an address in a contiguous view
+// of the address space on systems where the address space is
+// segmented. On other systems, it's just a normal address.
+type offAddr struct {
+ // a is just the virtual address, but should never be used
+ // directly. Call addr() to get this value instead.
+ a uintptr
+}
+
+// add adds a uintptr offset to the offAddr.
+func (l offAddr) add(bytes uintptr) offAddr {
+ return offAddr{a: l.a + bytes}
+}
+
+// sub subtracts a uintptr offset from the offAddr.
+func (l offAddr) sub(bytes uintptr) offAddr {
+ return offAddr{a: l.a - bytes}
+}
+
+// diff returns the amount of bytes in between the
+// two offAddrs.
+func (l1 offAddr) diff(l2 offAddr) uintptr {
+ return l1.a - l2.a
+}
+
+// lessThan returns true if l1 is less than l2 in the offset
+// address space.
+func (l1 offAddr) lessThan(l2 offAddr) bool {
+ return (l1.a - arenaBaseOffset) < (l2.a - arenaBaseOffset)
+}
+
+// lessEqual returns true if l1 is less than or equal to l2 in
+// the offset address space.
+func (l1 offAddr) lessEqual(l2 offAddr) bool {
+ return (l1.a - arenaBaseOffset) <= (l2.a - arenaBaseOffset)
+}
+
+// equal returns true if the two offAddr values are equal.
+func (l1 offAddr) equal(l2 offAddr) bool {
+ // No need to compare in the offset space, it
+ // means the same thing.
+ return l1 == l2
+}
+
+// addr returns the virtual address for this offset address.
+func (l offAddr) addr() uintptr {
+ return l.a
+}
+
// addrRanges is a data structure holding a collection of ranges of
// address space.
//
@@ -65,6 +155,10 @@ type addrRanges struct {
// ranges is a slice of ranges sorted by base.
ranges []addrRange
+ // totalBytes is the total amount of address space in bytes counted by
+ // this addrRanges.
+ totalBytes uintptr
+
// sysStat is the stat to track allocations by this type
sysStat *uint64
}
@@ -75,17 +169,19 @@ func (a *addrRanges) init(sysStat *uint64) {
ranges.cap = 16
ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), sys.PtrSize, sysStat))
a.sysStat = sysStat
+ a.totalBytes = 0
}
// findSucc returns the first index in a such that base is
// less than the base of the addrRange at that index.
-func (a *addrRanges) findSucc(base uintptr) int {
+func (a *addrRanges) findSucc(addr uintptr) int {
// TODO(mknyszek): Consider a binary search for large arrays.
// While iterating over these ranges is potentially expensive,
// the expected number of ranges is small, ideally just 1,
// since Go heaps are usually mostly contiguous.
+ base := offAddr{addr}
for i := range a.ranges {
- if base < a.ranges[i].base {
+ if base.lessThan(a.ranges[i].base) {
return i
}
}
@@ -116,9 +212,9 @@ func (a *addrRanges) add(r addrRange) {
// Because we assume r is not currently represented in a,
// findSucc gives us our insertion index.
- i := a.findSucc(r.base)
- coalescesDown := i > 0 && a.ranges[i-1].limit == r.base
- coalescesUp := i < len(a.ranges) && r.limit == a.ranges[i].base
+ i := a.findSucc(r.base.addr())
+ coalescesDown := i > 0 && a.ranges[i-1].limit.equal(r.base)
+ coalescesUp := i < len(a.ranges) && r.limit.equal(a.ranges[i].base)
if coalescesUp && coalescesDown {
// We have neighbors and they both border us.
// Merge a.ranges[i-1], r, and a.ranges[i] together into a.ranges[i-1].
@@ -158,4 +254,68 @@ func (a *addrRanges) add(r addrRange) {
}
a.ranges[i] = r
}
+ a.totalBytes += r.size()
+}
+
+// removeLast removes and returns the highest-addressed contiguous range
+// of a, or the last nBytes of that range, whichever is smaller. If a is
+// empty, it returns an empty range.
+func (a *addrRanges) removeLast(nBytes uintptr) addrRange {
+ if len(a.ranges) == 0 {
+ return addrRange{}
+ }
+ r := a.ranges[len(a.ranges)-1]
+ size := r.size()
+ if size > nBytes {
+ newEnd := r.limit.sub(nBytes)
+ a.ranges[len(a.ranges)-1].limit = newEnd
+ a.totalBytes -= nBytes
+ return addrRange{newEnd, r.limit}
+ }
+ a.ranges = a.ranges[:len(a.ranges)-1]
+ a.totalBytes -= size
+ return r
+}
+
+// removeGreaterEqual removes the ranges of a which are above addr, and additionally
+// splits any range containing addr.
+func (a *addrRanges) removeGreaterEqual(addr uintptr) {
+ pivot := a.findSucc(addr)
+ if pivot == 0 {
+ // addr is before all ranges in a.
+ a.totalBytes = 0
+ a.ranges = a.ranges[:0]
+ return
+ }
+ removed := uintptr(0)
+ for _, r := range a.ranges[pivot:] {
+ removed += r.size()
+ }
+ if r := a.ranges[pivot-1]; r.contains(addr) {
+ removed += r.size()
+ r = r.removeGreaterEqual(addr)
+ if r.size() == 0 {
+ pivot--
+ } else {
+ removed -= r.size()
+ a.ranges[pivot-1] = r
+ }
+ }
+ a.ranges = a.ranges[:pivot]
+ a.totalBytes -= removed
+}
+
+// cloneInto makes a deep clone of a's state into b, re-using
+// b's ranges if able.
+func (a *addrRanges) cloneInto(b *addrRanges) {
+ if len(a.ranges) > cap(b.ranges) {
+ // Grow the array.
+ ranges := (*notInHeapSlice)(unsafe.Pointer(&b.ranges))
+ ranges.len = 0
+ ranges.cap = cap(a.ranges)
+ ranges.array = (*notInHeap)(persistentalloc(unsafe.Sizeof(addrRange{})*uintptr(ranges.cap), sys.PtrSize, b.sysStat))
+ }
+ b.ranges = b.ranges[:len(a.ranges)]
+ b.totalBytes = a.totalBytes
+ copy(b.ranges, a.ranges)
}
diff --git a/src/runtime/mstats.go b/src/runtime/mstats.go
index ba508729c5..6a8a34d1ed 100644
--- a/src/runtime/mstats.go
+++ b/src/runtime/mstats.go
@@ -529,7 +529,7 @@ func updatememstats() {
// Calculate memory allocator stats.
// During program execution we only count number of frees and amount of freed memory.
- // Current number of alive object in the heap and amount of alive heap memory
+ // Current number of alive objects in the heap and amount of alive heap memory
// are calculated by scanning all spans.
// Total number of mallocs is calculated as number of frees plus number of alive objects.
// Similarly, total amount of allocated memory is calculated as amount of freed memory
diff --git a/src/runtime/mwbbuf.go b/src/runtime/mwbbuf.go
index f444452bab..632769c114 100644
--- a/src/runtime/mwbbuf.go
+++ b/src/runtime/mwbbuf.go
@@ -296,6 +296,13 @@ func wbBufFlush1(_p_ *p) {
continue
}
mbits.setMarked()
+
+ // Mark span.
+ arena, pageIdx, pageMask := pageIndexOf(span.base())
+ if arena.pageMarks[pageIdx]&pageMask == 0 {
+ atomic.Or8(&arena.pageMarks[pageIdx], pageMask)
+ }
+
if span.spanclass.noscan() {
gcw.bytesMarked += uint64(span.elemsize)
continue
diff --git a/src/runtime/netpoll_stub.go b/src/runtime/netpoll_stub.go
index f86f2f6174..3599f2d01b 100644
--- a/src/runtime/netpoll_stub.go
+++ b/src/runtime/netpoll_stub.go
@@ -49,6 +49,9 @@ func netpoll(delay int64) gList {
notetsleep(&netpollNote, delay)
unlock(&netpollStubLock)
+ // Guard against starvation in case the lock is contended
+ // (eg when running TestNetpollBreak).
+ osyield()
}
return gList{}
}
diff --git a/src/runtime/os_plan9.go b/src/runtime/os_plan9.go
index b534cdba5d..9e187d2220 100644
--- a/src/runtime/os_plan9.go
+++ b/src/runtime/os_plan9.go
@@ -293,7 +293,6 @@ func osinit() {
ncpu = getproccount()
physPageSize = getPageSize()
getg().m.procid = getpid()
- notify(unsafe.Pointer(funcPC(sigtramp)))
}
//go:nosplit
@@ -307,10 +306,10 @@ func getRandomData(r []byte) {
extendRandom(r, 0)
}
-func goenvs() {
-}
-
func initsig(preinit bool) {
+ if !preinit {
+ notify(unsafe.Pointer(funcPC(sigtramp)))
+ }
}
//go:nosplit
diff --git a/src/runtime/proc.go b/src/runtime/proc.go
index bd114496b2..2399f0a1d3 100644
--- a/src/runtime/proc.go
+++ b/src/runtime/proc.go
@@ -533,6 +533,7 @@ func cpuinit() {
// The new G calls runtime·main.
func schedinit() {
lockInit(&sched.lock, lockRankSched)
+ lockInit(&sched.sysmonlock, lockRankSysmon)
lockInit(&sched.deferlock, lockRankDefer)
lockInit(&sched.sudoglock, lockRankSudog)
lockInit(&deadlock, lockRankDeadlock)
@@ -760,6 +761,7 @@ func casfrom_Gscanstatus(gp *g, oldval, newval uint32) {
dumpgstatus(gp)
throw("casfrom_Gscanstatus: gp->status is not in scan state")
}
+ releaseLockRank(lockRankGscan)
}
// This will return false if the gp is not in the expected status and the cas fails.
@@ -771,7 +773,12 @@ func castogscanstatus(gp *g, oldval, newval uint32) bool {
_Gwaiting,
_Gsyscall:
if newval == oldval|_Gscan {
- return atomic.Cas(&gp.atomicstatus, oldval, newval)
+ r := atomic.Cas(&gp.atomicstatus, oldval, newval)
+ if r {
+ acquireLockRank(lockRankGscan)
+ }
+ return r
+
}
}
print("runtime: castogscanstatus oldval=", hex(oldval), " newval=", hex(newval), "\n")
@@ -792,6 +799,9 @@ func casgstatus(gp *g, oldval, newval uint32) {
})
}
+ acquireLockRank(lockRankGscan)
+ releaseLockRank(lockRankGscan)
+
// See https://golang.org/cl/21503 for justification of the yield delay.
const yieldDelay = 5 * 1000
var nextYield int64
@@ -842,6 +852,7 @@ func casGToPreemptScan(gp *g, old, new uint32) {
if old != _Grunning || new != _Gscan|_Gpreempted {
throw("bad g transition")
}
+ acquireLockRank(lockRankGscan)
for !atomic.Cas(&gp.atomicstatus, _Grunning, _Gscan|_Gpreempted) {
}
}
@@ -1691,8 +1702,7 @@ func lockextra(nilokay bool) *m {
for {
old := atomic.Loaduintptr(&extram)
if old == locked {
- yield := osyield
- yield()
+ osyield()
continue
}
if old == 0 && !nilokay {
@@ -1709,8 +1719,7 @@ func lockextra(nilokay bool) *m {
if atomic.Casuintptr(&extram, old, locked) {
return (*m)(unsafe.Pointer(old))
}
- yield := osyield
- yield()
+ osyield()
continue
}
}
@@ -1811,10 +1820,16 @@ func startTemplateThread() {
if GOARCH == "wasm" { // no threads on wasm yet
return
}
+
+ // Disable preemption to guarantee that the template thread will be
+ // created before a park once haveTemplateThread is set.
+ mp := acquirem()
if !atomic.Cas(&newmHandoff.haveTemplateThread, 0, 1) {
+ releasem(mp)
return
}
newm(templateThread, nil)
+ releasem(mp)
}
// templateThread is a thread in a known-good state that exists solely
@@ -2216,11 +2231,14 @@ top:
// Consider stealing timers from p2.
// This call to checkTimers is the only place where
// we hold a lock on a different P's timers.
- // Lock contention can be a problem here, so avoid
- // grabbing the lock if p2 is running and not marked
- // for preemption. If p2 is running and not being
- // preempted we assume it will handle its own timers.
- if i > 2 && shouldStealTimers(p2) {
+ // Lock contention can be a problem here, so
+ // initially avoid grabbing the lock if p2 is running
+ // and is not marked for preemption. If p2 is running
+ // and not being preempted we assume it will handle its
+ // own timers.
+ // If we're still looking for work after checking all
+ // the P's, then go ahead and steal from an active P.
+ if i > 2 || (i > 1 && shouldStealTimers(p2)) {
tnow, w, ran := checkTimers(p2, now)
now = tnow
if w != 0 && (pollUntil == 0 || w < pollUntil) {
@@ -2271,9 +2289,17 @@ stop:
// wasm only:
// If a callback returned and no other goroutine is awake,
- // then pause execution until a callback was triggered.
- if beforeIdle(delta) {
- // At least one goroutine got woken.
+ // then wake event handler goroutine which pauses execution
+ // until a callback was triggered.
+ gp, otherReady := beforeIdle(delta)
+ if gp != nil {
+ casgstatus(gp, _Gwaiting, _Grunnable)
+ if trace.enabled {
+ traceGoUnpark(gp, 0)
+ }
+ return gp, false
+ }
+ if otherReady {
goto top
}
@@ -4605,6 +4631,18 @@ func sysmon() {
}
unlock(&sched.lock)
}
+ lock(&sched.sysmonlock)
+ {
+ // If we spent a long time blocked on sysmonlock
+ // then we want to update now and next since it's
+ // likely stale.
+ now1 := nanotime()
+ if now1-now > 50*1000 /* 50µs */ {
+ next, _ = timeSleepUntil()
+ }
+ now = now1
+ }
+
// trigger libc interceptors if needed
if *cgo_yield != nil {
asmcgocall(*cgo_yield, nil)
@@ -4657,6 +4695,7 @@ func sysmon() {
lasttrace = now
schedtrace(debug.scheddetail > 0)
}
+ unlock(&sched.sysmonlock)
}
}
diff --git a/src/runtime/proc_test.go b/src/runtime/proc_test.go
index 764a279fca..de4dec36ce 100644
--- a/src/runtime/proc_test.go
+++ b/src/runtime/proc_test.go
@@ -7,6 +7,7 @@ package runtime_test
import (
"fmt"
"internal/race"
+ "internal/testenv"
"math"
"net"
"runtime"
@@ -929,6 +930,29 @@ func TestLockOSThreadAvoidsStatePropagation(t *testing.T) {
}
}
+func TestLockOSThreadTemplateThreadRace(t *testing.T) {
+ testenv.MustHaveGoRun(t)
+
+ exe, err := buildTestProg(t, "testprog")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ iterations := 100
+ if testing.Short() {
+ // Reduce run time to ~100ms, with much lower probability of
+ // catching issues.
+ iterations = 5
+ }
+ for i := 0; i < iterations; i++ {
+ want := "OK\n"
+ output := runBuiltTestProg(t, exe, "LockOSThreadTemplateThreadRace")
+ if output != want {
+ t.Fatalf("run %d: want %q, got %q", i, want, output)
+ }
+ }
+}
+
// fakeSyscall emulates a system call.
//go:nosplit
func fakeSyscall(duration time.Duration) {
diff --git a/src/runtime/rt0_openbsd_arm64.s b/src/runtime/rt0_openbsd_arm64.s
index ab8ea97f4f..12408f2eec 100644
--- a/src/runtime/rt0_openbsd_arm64.s
+++ b/src/runtime/rt0_openbsd_arm64.s
@@ -4,6 +4,12 @@
#include "textflag.h"
+// See comment in runtime/sys_openbsd_arm64.s re this construction.
+#define INVOKE_SYSCALL \
+ SVC; \
+ NOOP; \
+ NOOP
+
TEXT _rt0_arm64_openbsd(SB),NOSPLIT|NOFRAME,$0
MOVD 0(RSP), R0 // argc
ADD $8, RSP, R1 // argv
@@ -101,5 +107,5 @@ TEXT main(SB),NOSPLIT|NOFRAME,$0
exit:
MOVD $0, R0
MOVD $1, R8 // sys_exit
- SVC
+ INVOKE_SYSCALL
B exit
diff --git a/src/runtime/runtime-gdb.py b/src/runtime/runtime-gdb.py
index 6139f99485..8d96dfb609 100644
--- a/src/runtime/runtime-gdb.py
+++ b/src/runtime/runtime-gdb.py
@@ -18,6 +18,7 @@ path to this file based on the path to the runtime package.
from __future__ import print_function
import re
import sys
+import gdb
print("Loading Go Runtime support.", file=sys.stderr)
#http://python3porting.com/differences.html
@@ -98,11 +99,11 @@ class SliceValue:
# Pretty Printers
#
-
+# The patterns for matching types are permissive because gdb 8.2 switched to matching on (we think) typedef names instead of C syntax names.
class StringTypePrinter:
"Pretty print Go strings."
- pattern = re.compile(r'^struct string( \*)?$')
+ pattern = re.compile(r'^(struct string( \*)?|string)$')
def __init__(self, val):
self.val = val
@@ -118,7 +119,7 @@ class StringTypePrinter:
class SliceTypePrinter:
"Pretty print slices."
- pattern = re.compile(r'^struct \[\]')
+ pattern = re.compile(r'^(struct \[\]|\[\])')
def __init__(self, val):
self.val = val
@@ -127,7 +128,10 @@ class SliceTypePrinter:
return 'array'
def to_string(self):
- return str(self.val.type)[6:] # skip 'struct '
+ t = str(self.val.type)
+ if (t.startswith("struct ")):
+ return t[len("struct "):]
+ return t
def children(self):
sval = SliceValue(self.val)
@@ -195,7 +199,7 @@ class ChanTypePrinter:
to inspect their contents with this pretty printer.
"""
- pattern = re.compile(r'^struct hchan<.*>$')
+ pattern = re.compile(r'^chan ')
def __init__(self, val):
self.val = val
@@ -209,7 +213,7 @@ class ChanTypePrinter:
def children(self):
# see chan.c chanbuf(). et is the type stolen from hchan<T>::recvq->first->elem
et = [x.type for x in self.val['recvq']['first'].type.target().fields() if x.name == 'elem'][0]
- ptr = (self.val.address + 1).cast(et.pointer())
+ ptr = (self.val.address["buf"]).cast(et)
for i in range(self.val["qcount"]):
j = (self.val["recvx"] + i) % self.val["dataqsiz"]
yield ('[{0}]'.format(i), (ptr + j).dereference())
@@ -229,8 +233,6 @@ def makematcher(klass):
return matcher
goobjfile.pretty_printers.extend([makematcher(var) for var in vars().values() if hasattr(var, 'pattern')])
-
-
#
# Utilities
#
diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go
index 2dfa473514..e52bd1c4c4 100644
--- a/src/runtime/runtime-gdb_test.go
+++ b/src/runtime/runtime-gdb_test.go
@@ -19,6 +19,12 @@ import (
"testing"
)
+// NOTE: In some configurations, GDB will segfault when sent a SIGWINCH signal.
+// Some runtime tests send SIGWINCH to the entire process group, so those tests
+// must never run in parallel with GDB tests.
+//
+// See issue 39021 and https://sourceware.org/bugzilla/show_bug.cgi?id=26056.
+
func checkGdbEnvironment(t *testing.T) {
testenv.MustHaveGoBuild(t)
switch runtime.GOOS {
@@ -108,10 +114,18 @@ import "fmt"
import "runtime"
var gslice []string
func main() {
- go func() { select{} }() // ensure a second goroutine is running
mapvar := make(map[string]string, 13)
+ slicemap := make(map[string][]string,11)
+ chanint := make(chan int, 10)
+ chanstr := make(chan string, 10)
+ chanint <- 99
+ chanint <- 11
+ chanstr <- "spongepants"
+ chanstr <- "squarebob"
mapvar["abc"] = "def"
mapvar["ghi"] = "jkl"
+ slicemap["a"] = []string{"b","c","d"}
+ slicemap["e"] = []string{"f","g","h"}
strvar := "abc"
ptrvar := &strvar
slicevar := make([]string, 0, 16)
@@ -120,6 +134,7 @@ func main() {
runtime.KeepAlive(ptrvar)
_ = ptrvar // set breakpoint here
gslice = slicevar
+ fmt.Printf("%v, %v, %v\n", slicemap, <-chanint, <-chanstr)
runtime.KeepAlive(mapvar)
} // END_OF_PROGRAM
`
@@ -222,18 +237,24 @@ func testGdbPython(t *testing.T, cgo bool) {
"-ex", "echo BEGIN print mapvar\n",
"-ex", "print mapvar",
"-ex", "echo END\n",
+ "-ex", "echo BEGIN print slicemap\n",
+ "-ex", "print slicemap",
+ "-ex", "echo END\n",
"-ex", "echo BEGIN print strvar\n",
"-ex", "print strvar",
"-ex", "echo END\n",
+ "-ex", "echo BEGIN print chanint\n",
+ "-ex", "print chanint",
+ "-ex", "echo END\n",
+ "-ex", "echo BEGIN print chanstr\n",
+ "-ex", "print chanstr",
+ "-ex", "echo END\n",
"-ex", "echo BEGIN info locals\n",
"-ex", "info locals",
"-ex", "echo END\n",
"-ex", "echo BEGIN goroutine 1 bt\n",
"-ex", "goroutine 1 bt",
"-ex", "echo END\n",
- "-ex", "echo BEGIN goroutine 2 bt\n",
- "-ex", "goroutine 2 bt",
- "-ex", "echo END\n",
"-ex", "echo BEGIN goroutine all bt\n",
"-ex", "goroutine all bt",
"-ex", "echo END\n",
@@ -245,8 +266,11 @@ func testGdbPython(t *testing.T, cgo bool) {
"-ex", "echo END\n",
filepath.Join(dir, "a.exe"),
)
- got, _ := exec.Command("gdb", args...).CombinedOutput()
- t.Logf("gdb output: %s\n", got)
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
firstLine := bytes.SplitN(got, []byte("\n"), 2)[0]
if string(firstLine) != "Loading Go Runtime support." {
@@ -285,6 +309,23 @@ func testGdbPython(t *testing.T, cgo bool) {
t.Fatalf("print mapvar failed: %s", bl)
}
+ // 2 orders, and possible differences in spacing.
+ sliceMapSfx1 := `map[string][]string = {["e"] = []string = {"f", "g", "h"}, ["a"] = []string = {"b", "c", "d"}}`
+ sliceMapSfx2 := `map[string][]string = {["a"] = []string = {"b", "c", "d"}, ["e"] = []string = {"f", "g", "h"}}`
+ if bl := strings.ReplaceAll(blocks["print slicemap"], " ", " "); !strings.HasSuffix(bl, sliceMapSfx1) && !strings.HasSuffix(bl, sliceMapSfx2) {
+ t.Fatalf("print slicemap failed: %s", bl)
+ }
+
+ chanIntSfx := `chan int = {99, 11}`
+ if bl := strings.ReplaceAll(blocks["print chanint"], " ", " "); !strings.HasSuffix(bl, chanIntSfx) {
+ t.Fatalf("print chanint failed: %s", bl)
+ }
+
+ chanStrSfx := `chan string = {"spongepants", "squarebob"}`
+ if bl := strings.ReplaceAll(blocks["print chanstr"], " ", " "); !strings.HasSuffix(bl, chanStrSfx) {
+ t.Fatalf("print chanstr failed: %s", bl)
+ }
+
strVarRe := regexp.MustCompile(`^\$[0-9]+ = (0x[0-9a-f]+\s+)?"abc"$`)
if bl := blocks["print strvar"]; !strVarRe.MatchString(bl) {
t.Fatalf("print strvar failed: %s", bl)
@@ -310,7 +351,6 @@ func testGdbPython(t *testing.T, cgo bool) {
// Check that the backtraces are well formed.
checkCleanBacktrace(t, blocks["goroutine 1 bt"])
- checkCleanBacktrace(t, blocks["goroutine 2 bt"])
checkCleanBacktrace(t, blocks["goroutine 1 bt at the end"])
btGoroutine1Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?main\.main.+at`)
@@ -318,12 +358,7 @@ func testGdbPython(t *testing.T, cgo bool) {
t.Fatalf("goroutine 1 bt failed: %s", bl)
}
- btGoroutine2Re := regexp.MustCompile(`(?m)^#0\s+(0x[0-9a-f]+\s+in\s+)?runtime.+at`)
- if bl := blocks["goroutine 2 bt"]; !btGoroutine2Re.MatchString(bl) {
- t.Fatalf("goroutine 2 bt failed: %s", bl)
- }
-
- if bl := blocks["goroutine all bt"]; !btGoroutine1Re.MatchString(bl) || !btGoroutine2Re.MatchString(bl) {
+ if bl := blocks["goroutine all bt"]; !btGoroutine1Re.MatchString(bl) {
t.Fatalf("goroutine all bt failed: %s", bl)
}
@@ -398,7 +433,11 @@ func TestGdbBacktrace(t *testing.T) {
"-ex", "continue",
filepath.Join(dir, "a.exe"),
}
- got, _ := exec.Command("gdb", args...).CombinedOutput()
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
// Check that the backtrace matches the source code.
bt := []string{
@@ -413,8 +452,7 @@ func TestGdbBacktrace(t *testing.T) {
s := fmt.Sprintf("#%v.*main\\.%v", i, name)
re := regexp.MustCompile(s)
if found := re.Find(got) != nil; !found {
- t.Errorf("could not find '%v' in backtrace", s)
- t.Fatalf("gdb output:\n%v", string(got))
+ t.Fatalf("could not find '%v' in backtrace", s)
}
}
}
@@ -473,7 +511,11 @@ func TestGdbAutotmpTypes(t *testing.T) {
"-ex", "info types astruct",
filepath.Join(dir, "a.exe"),
}
- got, _ := exec.Command("gdb", args...).CombinedOutput()
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
sgot := string(got)
@@ -487,8 +529,7 @@ func TestGdbAutotmpTypes(t *testing.T) {
}
for _, name := range types {
if !strings.Contains(sgot, name) {
- t.Errorf("could not find %s in 'info typrs astruct' output", name)
- t.Fatalf("gdb output:\n%v", sgot)
+ t.Fatalf("could not find %s in 'info typrs astruct' output", name)
}
}
}
@@ -542,12 +583,14 @@ func TestGdbConst(t *testing.T) {
"-ex", "print 'runtime._PageSize'",
filepath.Join(dir, "a.exe"),
}
- got, _ := exec.Command("gdb", args...).CombinedOutput()
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
sgot := strings.ReplaceAll(string(got), "\r\n", "\n")
- t.Logf("output %q", sgot)
-
if !strings.Contains(sgot, "\n$1 = 42\n$2 = 18446744073709551615\n$3 = -1\n$4 = 1 '\\001'\n$5 = 8192") {
t.Fatalf("output mismatch")
}
@@ -602,7 +645,11 @@ func TestGdbPanic(t *testing.T) {
"-ex", "backtrace",
filepath.Join(dir, "a.exe"),
}
- got, _ := exec.Command("gdb", args...).CombinedOutput()
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
// Check that the backtrace matches the source code.
bt := []string{
@@ -613,8 +660,7 @@ func TestGdbPanic(t *testing.T) {
s := fmt.Sprintf("(#.* .* in )?main\\.%v", name)
re := regexp.MustCompile(s)
if found := re.Find(got) != nil; !found {
- t.Errorf("could not find '%v' in backtrace", s)
- t.Fatalf("gdb output:\n%v", string(got))
+ t.Fatalf("could not find '%v' in backtrace", s)
}
}
}
@@ -681,7 +727,11 @@ func TestGdbInfCallstack(t *testing.T) {
"-ex", "continue",
filepath.Join(dir, "a.exe"),
}
- got, _ := exec.Command("gdb", args...).CombinedOutput()
+ got, err := exec.Command("gdb", args...).CombinedOutput()
+ t.Logf("gdb output:\n%s", got)
+ if err != nil {
+ t.Fatalf("gdb exited with error: %v", err)
+ }
// Check that the backtrace matches
// We check the 3 inner most frames only as they are present certainly, according to gcc_<OS>_arm64.c
@@ -694,8 +744,7 @@ func TestGdbInfCallstack(t *testing.T) {
s := fmt.Sprintf("#%v.*%v", i, name)
re := regexp.MustCompile(s)
if found := re.Find(got) != nil; !found {
- t.Errorf("could not find '%v' in backtrace", s)
- t.Fatalf("gdb output:\n%v", string(got))
+ t.Fatalf("could not find '%v' in backtrace", s)
}
}
}
diff --git a/src/runtime/runtime2.go b/src/runtime/runtime2.go
index 2c566b5424..cffdb0bf27 100644
--- a/src/runtime/runtime2.go
+++ b/src/runtime/runtime2.go
@@ -349,12 +349,9 @@ type sudog struct {
g *g
- // isSelect indicates g is participating in a select, so
- // g.selectDone must be CAS'd to win the wake-up race.
- isSelect bool
- next *sudog
- prev *sudog
- elem unsafe.Pointer // data element (may point to stack)
+ next *sudog
+ prev *sudog
+ elem unsafe.Pointer // data element (may point to stack)
// The following fields are never accessed concurrently.
// For channels, waitlink is only accessed by g.
@@ -364,10 +361,15 @@ type sudog struct {
acquiretime int64
releasetime int64
ticket uint32
- parent *sudog // semaRoot binary tree
- waitlink *sudog // g.waiting list or semaRoot
- waittail *sudog // semaRoot
- c *hchan // channel
+
+ // isSelect indicates g is participating in a select, so
+ // g.selectDone must be CAS'd to win the wake-up race.
+ isSelect bool
+
+ parent *sudog // semaRoot binary tree
+ waitlink *sudog // g.waiting list or semaRoot
+ waittail *sudog // semaRoot
+ c *hchan // channel
}
type libcall struct {
@@ -766,6 +768,12 @@ type schedt struct {
procresizetime int64 // nanotime() of last change to gomaxprocs
totaltime int64 // ∫gomaxprocs dt up to procresizetime
+
+ // sysmonlock protects sysmon's actions on the runtime.
+ //
+ // Acquire and hold this mutex to block sysmon from interacting
+ // with the rest of the runtime.
+ sysmonlock mutex
}
// Values for the flags field of a sigTabT.
diff --git a/src/runtime/signal_unix.go b/src/runtime/signal_unix.go
index 5aedbf7778..dd6d79f8ec 100644
--- a/src/runtime/signal_unix.go
+++ b/src/runtime/signal_unix.go
@@ -432,6 +432,8 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
return
}
+ setg(g.m.gsignal)
+
// If some non-Go code called sigaltstack, adjust.
var gsignalStack gsignalStack
setStack := adjustSignalStack(sig, g.m, &gsignalStack)
@@ -439,8 +441,6 @@ func sigtrampgo(sig uint32, info *siginfo, ctx unsafe.Pointer) {
g.m.gsignal.stktopsp = getcallersp()
}
- setg(g.m.gsignal)
-
if g.stackguard0 == stackFork {
signalDuringFork(sig)
}
@@ -536,7 +536,7 @@ func sighandler(sig uint32, info *siginfo, ctxt unsafe.Pointer, gp *g) {
return
}
- if sig == sigPreempt {
+ if sig == sigPreempt && debug.asyncpreemptoff == 0 {
// Might be a preemption signal.
doSigPreempt(gp, c)
// Even if this was definitely a preemption signal, it
diff --git a/src/runtime/sizeof_test.go b/src/runtime/sizeof_test.go
index 852244d425..736e848f8c 100644
--- a/src/runtime/sizeof_test.go
+++ b/src/runtime/sizeof_test.go
@@ -21,7 +21,8 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms
}{
- {runtime.G{}, 216, 376}, // g, but exported for testing
+ {runtime.G{}, 216, 376}, // g, but exported for testing
+ {runtime.Sudog{}, 56, 88}, // sudog, but exported for testing
}
for _, tt := range tests {
diff --git a/src/runtime/slice.go b/src/runtime/slice.go
index 4ea4478601..0418ace25a 100644
--- a/src/runtime/slice.go
+++ b/src/runtime/slice.go
@@ -31,6 +31,55 @@ func panicmakeslicecap() {
panic(errorString("makeslice: cap out of range"))
}
+// makeslicecopy allocates a slice of "tolen" elements of type "et",
+// then copies "fromlen" elements of type "et" into that new allocation from "from".
+func makeslicecopy(et *_type, tolen int, fromlen int, from unsafe.Pointer) unsafe.Pointer {
+ var tomem, copymem uintptr
+ if uintptr(tolen) > uintptr(fromlen) {
+ var overflow bool
+ tomem, overflow = math.MulUintptr(et.size, uintptr(tolen))
+ if overflow || tomem > maxAlloc || tolen < 0 {
+ panicmakeslicelen()
+ }
+ copymem = et.size * uintptr(fromlen)
+ } else {
+ // fromlen is a known good length providing and equal or greater than tolen,
+ // thereby making tolen a good slice length too as from and to slices have the
+ // same element width.
+ tomem = et.size * uintptr(tolen)
+ copymem = tomem
+ }
+
+ var to unsafe.Pointer
+ if et.ptrdata == 0 {
+ to = mallocgc(tomem, nil, false)
+ if copymem < tomem {
+ memclrNoHeapPointers(add(to, copymem), tomem-copymem)
+ }
+ } else {
+ // Note: can't use rawmem (which avoids zeroing of memory), because then GC can scan uninitialized memory.
+ to = mallocgc(tomem, et, true)
+ if copymem > 0 && writeBarrier.enabled {
+ // Only shade the pointers in old.array since we know the destination slice to
+ // only contains nil pointers because it has been cleared during alloc.
+ bulkBarrierPreWriteSrcOnly(uintptr(to), uintptr(from), copymem)
+ }
+ }
+
+ if raceenabled {
+ callerpc := getcallerpc()
+ pc := funcPC(makeslicecopy)
+ racereadrangepc(from, copymem, callerpc, pc)
+ }
+ if msanenabled {
+ msanread(from, copymem)
+ }
+
+ memmove(to, from, copymem)
+
+ return to
+}
+
func makeslice(et *_type, len, cap int) unsafe.Pointer {
mem, overflow := math.MulUintptr(et.size, uintptr(cap))
if overflow || mem > maxAlloc || len < 0 || len > cap {
diff --git a/src/runtime/slice_test.go b/src/runtime/slice_test.go
index 0463fc70a7..e963a43dd3 100644
--- a/src/runtime/slice_test.go
+++ b/src/runtime/slice_test.go
@@ -10,6 +10,84 @@ import (
const N = 20
+func BenchmarkMakeSliceCopy(b *testing.B) {
+ const length = 32
+ var bytes = make([]byte, 8*length)
+ var ints = make([]int, length)
+ var ptrs = make([]*byte, length)
+ b.Run("mallocmove", func(b *testing.B) {
+ b.Run("Byte", func(b *testing.B) {
+ var x []byte
+ for i := 0; i < b.N; i++ {
+ x = make([]byte, len(bytes))
+ copy(x, bytes)
+ }
+ })
+ b.Run("Int", func(b *testing.B) {
+ var x []int
+ for i := 0; i < b.N; i++ {
+ x = make([]int, len(ints))
+ copy(x, ints)
+ }
+ })
+ b.Run("Ptr", func(b *testing.B) {
+ var x []*byte
+ for i := 0; i < b.N; i++ {
+ x = make([]*byte, len(ptrs))
+ copy(x, ptrs)
+ }
+
+ })
+ })
+ b.Run("makecopy", func(b *testing.B) {
+ b.Run("Byte", func(b *testing.B) {
+ var x []byte
+ for i := 0; i < b.N; i++ {
+ x = make([]byte, 8*length)
+ copy(x, bytes)
+ }
+ })
+ b.Run("Int", func(b *testing.B) {
+ var x []int
+ for i := 0; i < b.N; i++ {
+ x = make([]int, length)
+ copy(x, ints)
+ }
+ })
+ b.Run("Ptr", func(b *testing.B) {
+ var x []*byte
+ for i := 0; i < b.N; i++ {
+ x = make([]*byte, length)
+ copy(x, ptrs)
+ }
+
+ })
+ })
+ b.Run("nilappend", func(b *testing.B) {
+ b.Run("Byte", func(b *testing.B) {
+ var x []byte
+ for i := 0; i < b.N; i++ {
+ x = append([]byte(nil), bytes...)
+ _ = x
+ }
+ })
+ b.Run("Int", func(b *testing.B) {
+ var x []int
+ for i := 0; i < b.N; i++ {
+ x = append([]int(nil), ints...)
+ _ = x
+ }
+ })
+ b.Run("Ptr", func(b *testing.B) {
+ var x []*byte
+ for i := 0; i < b.N; i++ {
+ x = append([]*byte(nil), ptrs...)
+ _ = x
+ }
+ })
+ })
+}
+
type (
struct24 struct{ a, b, c int64 }
struct32 struct{ a, b, c, d int64 }
diff --git a/src/runtime/stack.go b/src/runtime/stack.go
index eeac66d1ce..0e930f60db 100644
--- a/src/runtime/stack.go
+++ b/src/runtime/stack.go
@@ -556,6 +556,7 @@ func adjustpointer(adjinfo *adjustinfo, vpp unsafe.Pointer) {
}
// Information from the compiler about the layout of stack frames.
+// Note: this type must agree with reflect.bitVector.
type bitvector struct {
n int32 // # of bits
bytedata *uint8
@@ -794,7 +795,16 @@ func syncadjustsudogs(gp *g, used uintptr, adjinfo *adjustinfo) uintptr {
var lastc *hchan
for sg := gp.waiting; sg != nil; sg = sg.waitlink {
if sg.c != lastc {
- lock(&sg.c.lock)
+ // There is a ranking cycle here between gscan bit and
+ // hchan locks. Normally, we only allow acquiring hchan
+ // locks and then getting a gscan bit. In this case, we
+ // already have the gscan bit. We allow acquiring hchan
+ // locks here as a special case, since a deadlock can't
+ // happen because the G involved must already be
+ // suspended. So, we get a special hchan lock rank here
+ // that is lower than gscan, but doesn't allow acquiring
+ // any other locks other than hchan.
+ lockWithRank(&sg.c.lock, lockRankHchanLeaf)
}
lastc = sg.c
}
@@ -1033,6 +1043,17 @@ func newstack() {
// Allocate a bigger segment and move the stack.
oldsize := gp.stack.hi - gp.stack.lo
newsize := oldsize * 2
+
+ // Make sure we grow at least as much as needed to fit the new frame.
+ // (This is just an optimization - the caller of morestack will
+ // recheck the bounds on return.)
+ if f := findfunc(gp.sched.pc); f.valid() {
+ max := uintptr(funcMaxSPDelta(f))
+ for newsize-oldsize < max+_StackGuard {
+ newsize *= 2
+ }
+ }
+
if newsize > maxstacksize {
print("runtime: goroutine stack exceeds ", maxstacksize, "-byte limit\n")
print("runtime: sp=", hex(sp), " stack=[", hex(gp.stack.lo), ", ", hex(gp.stack.hi), "]\n")
diff --git a/src/runtime/stubs.go b/src/runtime/stubs.go
index 2c6f027c2c..b891a12fdd 100644
--- a/src/runtime/stubs.go
+++ b/src/runtime/stubs.go
@@ -130,7 +130,7 @@ func fastrandn(n uint32) uint32 {
//go:linkname sync_fastrand sync.fastrand
func sync_fastrand() uint32 { return fastrand() }
-// in asm_*.s
+// in internal/bytealg/equal_*.s
//go:noescape
func memequal(a, b unsafe.Pointer, size uintptr) bool
diff --git a/src/runtime/symtab.go b/src/runtime/symtab.go
index ce2ec6dd1d..1e86662adc 100644
--- a/src/runtime/symtab.go
+++ b/src/runtime/symtab.go
@@ -563,8 +563,8 @@ func moduledataverify1(datap *moduledata) {
// given program counter address, or else nil.
//
// If pc represents multiple functions because of inlining, it returns
-// the a *Func describing the innermost function, but with an entry
-// of the outermost function.
+// the *Func describing the innermost function, but with an entry of
+// the outermost function.
func FuncForPC(pc uintptr) *Func {
f := findfunc(pc)
if !f.valid() {
diff --git a/src/runtime/sys_darwin.go b/src/runtime/sys_darwin.go
index 1b136f88a8..28c500a710 100644
--- a/src/runtime/sys_darwin.go
+++ b/src/runtime/sys_darwin.go
@@ -127,6 +127,19 @@ func syscall_rawSyscall6(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintpt
return
}
+// syscallNoErr is used in crypto/x509 to call into Security.framework and CF.
+
+//go:linkname crypto_x509_syscall crypto/x509/internal/macOS.syscall
+//go:nosplit
+//go:cgo_unsafe_args
+func crypto_x509_syscall(fn, a1, a2, a3, a4, a5, a6 uintptr) (r1 uintptr) {
+ entersyscall()
+ libcCall(unsafe.Pointer(funcPC(syscallNoErr)), unsafe.Pointer(&fn))
+ exitsyscall()
+ return
+}
+func syscallNoErr()
+
// The *_trampoline functions convert from the Go calling convention to the C calling convention
// and then call the underlying libc function. They are defined in sys_darwin_$ARCH.s.
@@ -477,6 +490,8 @@ func setNonblock(fd int32) {
//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.
+// Magic incantation to get libSystem and friends actually dynamically linked.
// TODO: Why does the code require this? See cmd/link/internal/ld/go.go
//go:cgo_import_dynamic _ _ "/usr/lib/libSystem.B.dylib"
+//go:cgo_import_dynamic _ _ "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+//go:cgo_import_dynamic _ _ "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
diff --git a/src/runtime/sys_darwin_amd64.s b/src/runtime/sys_darwin_amd64.s
index a45ea42e5d..825852d673 100644
--- a/src/runtime/sys_darwin_amd64.s
+++ b/src/runtime/sys_darwin_amd64.s
@@ -825,3 +825,29 @@ ok:
MOVQ BP, SP
POPQ BP
RET
+
+// syscallNoErr is like syscall6 but does not check for errors, and
+// only returns one value, for use with standard C ABI library functions.
+TEXT runtime·syscallNoErr(SB),NOSPLIT,$0
+ PUSHQ BP
+ MOVQ SP, BP
+ SUBQ $16, SP
+ MOVQ (0*8)(DI), R11// fn
+ MOVQ (2*8)(DI), SI // a2
+ MOVQ (3*8)(DI), DX // a3
+ MOVQ (4*8)(DI), CX // a4
+ MOVQ (5*8)(DI), R8 // a5
+ MOVQ (6*8)(DI), R9 // a6
+ MOVQ DI, (SP)
+ MOVQ (1*8)(DI), DI // a1
+ XORL AX, AX // vararg: say "no float args"
+
+ CALL R11
+
+ MOVQ (SP), DI
+ MOVQ AX, (7*8)(DI) // r1
+
+ XORL AX, AX // no error (it's ignored anyway)
+ MOVQ BP, SP
+ POPQ BP
+ RET
diff --git a/src/runtime/sys_openbsd_arm.s b/src/runtime/sys_openbsd_arm.s
index 11f6e00100..9e18ce0e16 100644
--- a/src/runtime/sys_openbsd_arm.s
+++ b/src/runtime/sys_openbsd_arm.s
@@ -13,11 +13,23 @@
#define CLOCK_REALTIME $0
#define CLOCK_MONOTONIC $3
+// With OpenBSD 6.7 onwards, an armv7 syscall returns two instructions
+// after the SWI instruction, to allow for a speculative execution
+// barrier to be placed after the SWI without impacting performance.
+// For now use hardware no-ops as this works with both older and newer
+// kernels. After OpenBSD 6.8 is released this should be changed to
+// speculation barriers.
+#define NOOP MOVW R0, R0
+#define INVOKE_SYSCALL \
+ SWI $0; \
+ NOOP; \
+ NOOP
+
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
MOVW code+0(FP), R0 // arg 1 - status
MOVW $1, R12 // sys_exit
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -26,7 +38,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
TEXT runtime·exitThread(SB),NOSPLIT,$0-4
MOVW wait+0(FP), R0 // arg 1 - notdead
MOVW $302, R12 // sys___threxit
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $1, R8 // crash on syscall failure
MOVW.CS R8, (R8)
JMP 0(PC)
@@ -36,7 +48,7 @@ TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
MOVW mode+4(FP), R1 // arg 2 - mode
MOVW perm+8(FP), R2 // arg 3 - perm
MOVW $5, R12 // sys_open
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $-1, R0
MOVW R0, ret+12(FP)
RET
@@ -44,7 +56,7 @@ TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0
MOVW fd+0(FP), R0 // arg 1 - fd
MOVW $6, R12 // sys_close
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $-1, R0
MOVW R0, ret+4(FP)
RET
@@ -54,7 +66,7 @@ TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0
MOVW p+4(FP), R1 // arg 2 - buf
MOVW n+8(FP), R2 // arg 3 - nbyte
MOVW $3, R12 // sys_read
- SWI $0
+ INVOKE_SYSCALL
RSB.CS $0, R0 // caller expects negative errno
MOVW R0, ret+12(FP)
RET
@@ -63,7 +75,7 @@ TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0
TEXT runtime·pipe(SB),NOSPLIT,$0-12
MOVW $r+0(FP), R0
MOVW $263, R12
- SWI $0
+ INVOKE_SYSCALL
MOVW R0, errno+8(FP)
RET
@@ -72,7 +84,7 @@ TEXT runtime·pipe2(SB),NOSPLIT,$0-16
MOVW $r+4(FP), R0
MOVW flags+0(FP), R1
MOVW $101, R12
- SWI $0
+ INVOKE_SYSCALL
MOVW R0, errno+12(FP)
RET
@@ -81,7 +93,7 @@ TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0
MOVW p+4(FP), R1 // arg 2 - buf
MOVW n+8(FP), R2 // arg 3 - nbyte
MOVW $4, R12 // sys_write
- SWI $0
+ INVOKE_SYSCALL
RSB.CS $0, R0 // caller expects negative errno
MOVW R0, ret+12(FP)
RET
@@ -99,12 +111,12 @@ TEXT runtime·usleep(SB),NOSPLIT,$16
MOVW $4(R13), R0 // arg 1 - rqtp
MOVW $0, R1 // arg 2 - rmtp
MOVW $91, R12 // sys_nanosleep
- SWI $0
+ INVOKE_SYSCALL
RET
TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVW $299, R12 // sys_getthrid
- SWI $0
+ INVOKE_SYSCALL
MOVW R0, ret+0(FP)
RET
@@ -113,16 +125,16 @@ TEXT runtime·thrkill(SB),NOSPLIT,$0-8
MOVW sig+4(FP), R1 // arg 2 - signum
MOVW $0, R2 // arg 3 - tcb
MOVW $119, R12 // sys_thrkill
- SWI $0
+ INVOKE_SYSCALL
RET
TEXT runtime·raiseproc(SB),NOSPLIT,$12
- MOVW $20, R12
- SWI $0 // sys_getpid
+ MOVW $20, R12 // sys_getpid
+ INVOKE_SYSCALL
// arg 1 - pid, already in R0
MOVW sig+0(FP), R1 // arg 2 - signum
MOVW $122, R12 // sys_kill
- SWI $0
+ INVOKE_SYSCALL
RET
TEXT runtime·mmap(SB),NOSPLIT,$16
@@ -140,7 +152,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$16
MOVW R7, 16(R13) // high 32 bits
ADD $4, R13
MOVW $197, R12 // sys_mmap
- SWI $0
+ INVOKE_SYSCALL
SUB $4, R13
MOVW $0, R1
MOVW.CS R0, R1 // if error, move to R1
@@ -153,7 +165,7 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
MOVW addr+0(FP), R0 // arg 1 - addr
MOVW n+4(FP), R1 // arg 2 - len
MOVW $73, R12 // sys_munmap
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -163,7 +175,7 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
MOVW n+4(FP), R1 // arg 2 - len
MOVW flags+8(FP), R2 // arg 2 - flags
MOVW $75, R12 // sys_madvise
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $-1, R0
MOVW R0, ret+12(FP)
RET
@@ -173,7 +185,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
MOVW new+4(FP), R1 // arg 2 - new value
MOVW old+8(FP), R2 // arg 3 - old value
MOVW $69, R12 // sys_setitimer
- SWI $0
+ INVOKE_SYSCALL
RET
// func walltime1() (sec int64, nsec int32)
@@ -181,7 +193,7 @@ TEXT runtime·walltime1(SB), NOSPLIT, $32
MOVW CLOCK_REALTIME, R0 // arg 1 - clock_id
MOVW $8(R13), R1 // arg 2 - tp
MOVW $87, R12 // sys_clock_gettime
- SWI $0
+ INVOKE_SYSCALL
MOVW 8(R13), R0 // sec - l32
MOVW 12(R13), R1 // sec - h32
@@ -199,7 +211,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$32
MOVW CLOCK_MONOTONIC, R0 // arg 1 - clock_id
MOVW $8(R13), R1 // arg 2 - tp
MOVW $87, R12 // sys_clock_gettime
- SWI $0
+ INVOKE_SYSCALL
MOVW 8(R13), R0 // sec - l32
MOVW 12(R13), R4 // sec - h32
@@ -220,7 +232,7 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0
MOVW new+4(FP), R1 // arg 2 - new sigaction
MOVW old+8(FP), R2 // arg 3 - old sigaction
MOVW $46, R12 // sys_sigaction
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $3, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
@@ -229,7 +241,7 @@ TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0
MOVW how+0(FP), R0 // arg 1 - mode
MOVW new+4(FP), R1 // arg 2 - new
MOVW $48, R12 // sys_sigprocmask
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $3, R8 // crash on syscall failure
MOVW.CS R8, (R8)
MOVW R0, ret+8(FP)
@@ -280,7 +292,7 @@ TEXT runtime·tfork(SB),NOSPLIT,$0
MOVW param+0(FP), R0 // arg 1 - param
MOVW psize+4(FP), R1 // arg 2 - psize
MOVW $8, R12 // sys___tfork
- SWI $0
+ INVOKE_SYSCALL
// Return if syscall failed.
B.CC 4(PC)
@@ -313,14 +325,14 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
MOVW new+0(FP), R0 // arg 1 - new sigaltstack
MOVW old+4(FP), R1 // arg 2 - old sigaltstack
MOVW $288, R12 // sys_sigaltstack
- SWI $0
+ INVOKE_SYSCALL
MOVW.CS $0, R8 // crash on syscall failure
MOVW.CS R8, (R8)
RET
TEXT runtime·osyield(SB),NOSPLIT,$0
MOVW $298, R12 // sys_sched_yield
- SWI $0
+ INVOKE_SYSCALL
RET
TEXT runtime·thrsleep(SB),NOSPLIT,$4
@@ -332,7 +344,7 @@ TEXT runtime·thrsleep(SB),NOSPLIT,$4
MOVW R4, 4(R13)
ADD $4, R13
MOVW $94, R12 // sys___thrsleep
- SWI $0
+ INVOKE_SYSCALL
SUB $4, R13
MOVW R0, ret+20(FP)
RET
@@ -341,7 +353,7 @@ TEXT runtime·thrwakeup(SB),NOSPLIT,$0
MOVW ident+0(FP), R0 // arg 1 - ident
MOVW n+4(FP), R1 // arg 2 - n
MOVW $301, R12 // sys___thrwakeup
- SWI $0
+ INVOKE_SYSCALL
MOVW R0, ret+8(FP)
RET
@@ -356,7 +368,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$8
MOVW R5, 8(R13)
ADD $4, R13
MOVW $202, R12 // sys___sysctl
- SWI $0
+ INVOKE_SYSCALL
SUB $4, R13
MOVW.CC $0, R0
RSB.CS $0, R0
@@ -366,7 +378,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$8
// int32 runtime·kqueue(void);
TEXT runtime·kqueue(SB),NOSPLIT,$0
MOVW $269, R12 // sys_kqueue
- SWI $0
+ INVOKE_SYSCALL
RSB.CS $0, R0
MOVW R0, ret+0(FP)
RET
@@ -383,7 +395,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$8
MOVW R5, 8(R13)
ADD $4, R13
MOVW $72, R12 // sys_kevent
- SWI $0
+ INVOKE_SYSCALL
RSB.CS $0, R0
SUB $4, R13
MOVW R0, ret+24(FP)
@@ -395,7 +407,7 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVW $2, R1 // arg 2 - cmd (F_SETFD)
MOVW $1, R2 // arg 3 - arg (FD_CLOEXEC)
MOVW $92, R12 // sys_fcntl
- SWI $0
+ INVOKE_SYSCALL
RET
// func runtime·setNonblock(fd int32)
@@ -404,12 +416,12 @@ TEXT runtime·setNonblock(SB),NOSPLIT,$0-4
MOVW $3, R1 // F_GETFL
MOVW $0, R2
MOVW $92, R12
- SWI $0
+ INVOKE_SYSCALL
ORR $0x4, R0, R2 // O_NONBLOCK
MOVW fd+0(FP), R0 // fd
MOVW $4, R1 // F_SETFL
MOVW $92, R12
- SWI $0
+ INVOKE_SYSCALL
RET
TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
@@ -418,6 +430,6 @@ TEXT ·publicationBarrier(SB),NOSPLIT|NOFRAME,$0-0
TEXT runtime·read_tls_fallback(SB),NOSPLIT|NOFRAME,$0
MOVM.WP [R1, R2, R3, R12], (R13)
MOVW $330, R12 // sys___get_tcb
- SWI $0
+ INVOKE_SYSCALL
MOVM.IAW (R13), [R1, R2, R3, R12]
RET
diff --git a/src/runtime/sys_openbsd_arm64.s b/src/runtime/sys_openbsd_arm64.s
index 839aa57062..621b1b1a42 100644
--- a/src/runtime/sys_openbsd_arm64.s
+++ b/src/runtime/sys_openbsd_arm64.s
@@ -13,11 +13,22 @@
#define CLOCK_REALTIME $0
#define CLOCK_MONOTONIC $3
+// With OpenBSD 6.7 onwards, an arm64 syscall returns two instructions
+// after the SVC instruction, to allow for a speculative execution
+// barrier to be placed after the SVC without impacting performance.
+// For now use hardware no-ops as this works with both older and newer
+// kernels. After OpenBSD 6.8 is released this should be changed to
+// speculation barriers.
+#define INVOKE_SYSCALL \
+ SVC; \
+ NOOP; \
+ NOOP
+
// Exit the entire program (like C exit)
TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
MOVW code+0(FP), R0 // arg 1 - status
MOVD $1, R8 // sys_exit
- SVC
+ INVOKE_SYSCALL
BCC 3(PC)
MOVD $0, R0 // crash on syscall failure
MOVD R0, (R0)
@@ -27,7 +38,7 @@ TEXT runtime·exit(SB),NOSPLIT|NOFRAME,$0
TEXT runtime·exitThread(SB),NOSPLIT,$0
MOVD wait+0(FP), R0 // arg 1 - notdead
MOVD $302, R8 // sys___threxit
- SVC
+ INVOKE_SYSCALL
MOVD $0, R0 // crash on syscall failure
MOVD R0, (R0)
JMP 0(PC)
@@ -37,7 +48,7 @@ TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
MOVW mode+8(FP), R1 // arg 2 - mode
MOVW perm+12(FP), R2 // arg 3 - perm
MOVD $5, R8 // sys_open
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
MOVW $-1, R0
MOVW R0, ret+16(FP)
@@ -46,7 +57,7 @@ TEXT runtime·open(SB),NOSPLIT|NOFRAME,$0
TEXT runtime·closefd(SB),NOSPLIT|NOFRAME,$0
MOVW fd+0(FP), R0 // arg 1 - fd
MOVD $6, R8 // sys_close
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
MOVW $-1, R0
MOVW R0, ret+8(FP)
@@ -57,7 +68,7 @@ TEXT runtime·read(SB),NOSPLIT|NOFRAME,$0
MOVD p+8(FP), R1 // arg 2 - buf
MOVW n+16(FP), R2 // arg 3 - nbyte
MOVD $3, R8 // sys_read
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+24(FP)
@@ -68,7 +79,7 @@ TEXT runtime·pipe(SB),NOSPLIT|NOFRAME,$0-12
MOVD $r+0(FP), R0
MOVW $0, R1
MOVD $101, R8 // sys_pipe2
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, errno+8(FP)
@@ -79,7 +90,7 @@ TEXT runtime·pipe2(SB),NOSPLIT|NOFRAME,$0-20
MOVD $r+8(FP), R0
MOVW flags+0(FP), R1
MOVD $101, R8 // sys_pipe2
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, errno+16(FP)
@@ -90,7 +101,7 @@ TEXT runtime·write1(SB),NOSPLIT|NOFRAME,$0
MOVD p+8(FP), R1 // arg 2 - buf
MOVW n+16(FP), R2 // arg 3 - nbyte
MOVD $4, R8 // sys_write
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+24(FP)
@@ -111,12 +122,12 @@ TEXT runtime·usleep(SB),NOSPLIT,$24-4
ADD $8, RSP, R0 // arg 1 - rqtp
MOVD $0, R1 // arg 2 - rmtp
MOVD $91, R8 // sys_nanosleep
- SVC
+ INVOKE_SYSCALL
RET
TEXT runtime·getthrid(SB),NOSPLIT,$0-4
MOVD $299, R8 // sys_getthrid
- SVC
+ INVOKE_SYSCALL
MOVW R0, ret+0(FP)
RET
@@ -125,16 +136,16 @@ TEXT runtime·thrkill(SB),NOSPLIT,$0-16
MOVD sig+8(FP), R1 // arg 2 - signum
MOVW $0, R2 // arg 3 - tcb
MOVD $119, R8 // sys_thrkill
- SVC
+ INVOKE_SYSCALL
RET
TEXT runtime·raiseproc(SB),NOSPLIT,$0
MOVD $20, R8 // sys_getpid
- SVC
+ INVOKE_SYSCALL
// arg 1 - pid, already in R0
MOVW sig+0(FP), R1 // arg 2 - signum
MOVD $122, R8 // sys_kill
- SVC
+ INVOKE_SYSCALL
RET
TEXT runtime·mmap(SB),NOSPLIT,$0
@@ -146,7 +157,7 @@ TEXT runtime·mmap(SB),NOSPLIT,$0
MOVW $0, R5 // arg 6 - pad
MOVW off+28(FP), R6 // arg 7 - offset
MOVD $197, R8 // sys_mmap
- SVC
+ INVOKE_SYSCALL
MOVD $0, R1
BCC 3(PC)
MOVD R0, R1 // if error, move to R1
@@ -159,7 +170,7 @@ TEXT runtime·munmap(SB),NOSPLIT,$0
MOVD addr+0(FP), R0 // arg 1 - addr
MOVD n+8(FP), R1 // arg 2 - len
MOVD $73, R8 // sys_munmap
- SVC
+ INVOKE_SYSCALL
BCC 3(PC)
MOVD $0, R0 // crash on syscall failure
MOVD R0, (R0)
@@ -170,7 +181,7 @@ TEXT runtime·madvise(SB),NOSPLIT,$0
MOVD n+8(FP), R1 // arg 2 - len
MOVW flags+16(FP), R2 // arg 2 - flags
MOVD $75, R8 // sys_madvise
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
MOVW $-1, R0
MOVW R0, ret+24(FP)
@@ -181,7 +192,7 @@ TEXT runtime·setitimer(SB),NOSPLIT,$0
MOVD new+8(FP), R1 // arg 2 - new value
MOVD old+16(FP), R2 // arg 3 - old value
MOVD $69, R8 // sys_setitimer
- SVC
+ INVOKE_SYSCALL
RET
// func walltime1() (sec int64, nsec int32)
@@ -189,7 +200,7 @@ TEXT runtime·walltime1(SB), NOSPLIT, $32
MOVW CLOCK_REALTIME, R0 // arg 1 - clock_id
MOVD $8(RSP), R1 // arg 2 - tp
MOVD $87, R8 // sys_clock_gettime
- SVC
+ INVOKE_SYSCALL
MOVD 8(RSP), R0 // sec
MOVD 16(RSP), R1 // nsec
@@ -204,7 +215,7 @@ TEXT runtime·nanotime1(SB),NOSPLIT,$32
MOVW CLOCK_MONOTONIC, R0 // arg 1 - clock_id
MOVD $8(RSP), R1 // arg 2 - tp
MOVD $87, R8 // sys_clock_gettime
- SVC
+ INVOKE_SYSCALL
MOVW 8(RSP), R3 // sec
MOVW 16(RSP), R5 // nsec
@@ -220,7 +231,7 @@ TEXT runtime·sigaction(SB),NOSPLIT,$0
MOVD new+8(FP), R1 // arg 2 - new sigaction
MOVD old+16(FP), R2 // arg 3 - old sigaction
MOVD $46, R8 // sys_sigaction
- SVC
+ INVOKE_SYSCALL
BCC 3(PC)
MOVD $3, R0 // crash on syscall failure
MOVD R0, (R0)
@@ -230,7 +241,7 @@ TEXT runtime·obsdsigprocmask(SB),NOSPLIT,$0
MOVW how+0(FP), R0 // arg 1 - mode
MOVW new+4(FP), R1 // arg 2 - new
MOVD $48, R8 // sys_sigprocmask
- SVC
+ INVOKE_SYSCALL
BCC 3(PC)
MOVD $3, R8 // crash on syscall failure
MOVD R8, (R8)
@@ -314,7 +325,7 @@ TEXT runtime·tfork(SB),NOSPLIT,$0
MOVD param+0(FP), R0 // arg 1 - param
MOVD psize+8(FP), R1 // arg 2 - psize
MOVD $8, R8 // sys___tfork
- SVC
+ INVOKE_SYSCALL
// Return if syscall failed.
BCC 4(PC)
@@ -344,7 +355,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
MOVD new+0(FP), R0 // arg 1 - new sigaltstack
MOVD old+8(FP), R1 // arg 2 - old sigaltstack
MOVD $288, R8 // sys_sigaltstack
- SVC
+ INVOKE_SYSCALL
BCC 3(PC)
MOVD $0, R8 // crash on syscall failure
MOVD R8, (R8)
@@ -352,7 +363,7 @@ TEXT runtime·sigaltstack(SB),NOSPLIT,$0
TEXT runtime·osyield(SB),NOSPLIT,$0
MOVD $298, R8 // sys_sched_yield
- SVC
+ INVOKE_SYSCALL
RET
TEXT runtime·thrsleep(SB),NOSPLIT,$0
@@ -362,7 +373,7 @@ TEXT runtime·thrsleep(SB),NOSPLIT,$0
MOVD lock+24(FP), R3 // arg 4 - lock
MOVD abort+32(FP), R4 // arg 5 - abort
MOVD $94, R8 // sys___thrsleep
- SVC
+ INVOKE_SYSCALL
MOVW R0, ret+40(FP)
RET
@@ -370,7 +381,7 @@ TEXT runtime·thrwakeup(SB),NOSPLIT,$0
MOVD ident+0(FP), R0 // arg 1 - ident
MOVW n+8(FP), R1 // arg 2 - n
MOVD $301, R8 // sys___thrwakeup
- SVC
+ INVOKE_SYSCALL
MOVW R0, ret+16(FP)
RET
@@ -382,7 +393,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
MOVD dst+32(FP), R4 // arg 5 - dest
MOVD ndst+40(FP), R5 // arg 6 - newlen
MOVD $202, R8 // sys___sysctl
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+48(FP)
@@ -391,7 +402,7 @@ TEXT runtime·sysctl(SB),NOSPLIT,$0
// int32 runtime·kqueue(void);
TEXT runtime·kqueue(SB),NOSPLIT,$0
MOVD $269, R8 // sys_kqueue
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+0(FP)
@@ -406,7 +417,7 @@ TEXT runtime·kevent(SB),NOSPLIT,$0
MOVW nev+32(FP), R4 // arg 5 - nevents
MOVD ts+40(FP), R5 // arg 6 - timeout
MOVD $72, R8 // sys_kevent
- SVC
+ INVOKE_SYSCALL
BCC 2(PC)
NEG R0, R0
MOVW R0, ret+48(FP)
@@ -418,7 +429,7 @@ TEXT runtime·closeonexec(SB),NOSPLIT,$0
MOVD $2, R1 // arg 2 - cmd (F_SETFD)
MOVD $1, R2 // arg 3 - arg (FD_CLOEXEC)
MOVD $92, R8 // sys_fcntl
- SVC
+ INVOKE_SYSCALL
RET
// func runtime·setNonblock(int32 fd)
@@ -427,11 +438,11 @@ TEXT runtime·setNonblock(SB),NOSPLIT|NOFRAME,$0-4
MOVD $3, R1 // arg 2 - cmd (F_GETFL)
MOVD $0, R2 // arg 3
MOVD $92, R8 // sys_fcntl
- SVC
+ INVOKE_SYSCALL
MOVD $4, R2 // O_NONBLOCK
ORR R0, R2 // arg 3 - flags
MOVW fd+0(FP), R0 // arg 1 - fd
MOVD $4, R1 // arg 2 - cmd (F_SETFL)
MOVD $92, R8 // sys_fcntl
- SVC
+ INVOKE_SYSCALL
RET
diff --git a/src/runtime/testdata/testprog/gc.go b/src/runtime/testdata/testprog/gc.go
index f691a1d127..74732cd9f4 100644
--- a/src/runtime/testdata/testprog/gc.go
+++ b/src/runtime/testdata/testprog/gc.go
@@ -11,6 +11,7 @@ import (
"runtime/debug"
"sync/atomic"
"time"
+ "unsafe"
)
func init() {
@@ -19,6 +20,7 @@ func init() {
register("GCSys", GCSys)
register("GCPhys", GCPhys)
register("DeferLiveness", DeferLiveness)
+ register("GCZombie", GCZombie)
}
func GCSys() {
@@ -264,3 +266,37 @@ func DeferLiveness() {
func escape(x interface{}) { sink2 = x; sink2 = nil }
var sink2 interface{}
+
+// Test zombie object detection and reporting.
+func GCZombie() {
+ // Allocate several objects of unusual size (so free slots are
+ // unlikely to all be re-allocated by the runtime).
+ const size = 190
+ const count = 8192 / size
+ keep := make([]*byte, 0, (count+1)/2)
+ free := make([]uintptr, 0, (count+1)/2)
+ zombies := make([]*byte, 0, len(free))
+ for i := 0; i < count; i++ {
+ obj := make([]byte, size)
+ p := &obj[0]
+ if i%2 == 0 {
+ keep = append(keep, p)
+ } else {
+ free = append(free, uintptr(unsafe.Pointer(p)))
+ }
+ }
+
+ // Free the unreferenced objects.
+ runtime.GC()
+
+ // Bring the free objects back to life.
+ for _, p := range free {
+ zombies = append(zombies, (*byte)(unsafe.Pointer(p)))
+ }
+
+ // GC should detect the zombie objects.
+ runtime.GC()
+ println("failed")
+ runtime.KeepAlive(keep)
+ runtime.KeepAlive(zombies)
+}
diff --git a/src/runtime/testdata/testprog/lockosthread.go b/src/runtime/testdata/testprog/lockosthread.go
index fd3123e647..e9d7fdbc44 100644
--- a/src/runtime/testdata/testprog/lockosthread.go
+++ b/src/runtime/testdata/testprog/lockosthread.go
@@ -7,6 +7,7 @@ package main
import (
"os"
"runtime"
+ "sync"
"time"
)
@@ -30,6 +31,7 @@ func init() {
runtime.LockOSThread()
})
register("LockOSThreadAvoidsStatePropagation", LockOSThreadAvoidsStatePropagation)
+ register("LockOSThreadTemplateThreadRace", LockOSThreadTemplateThreadRace)
}
func LockOSThreadMain() {
@@ -195,3 +197,50 @@ func LockOSThreadAvoidsStatePropagation() {
runtime.UnlockOSThread()
println("OK")
}
+
+func LockOSThreadTemplateThreadRace() {
+ // This test attempts to reproduce the race described in
+ // golang.org/issue/38931. To do so, we must have a stop-the-world
+ // (achieved via ReadMemStats) racing with two LockOSThread calls.
+ //
+ // While this test attempts to line up the timing, it is only expected
+ // to fail (and thus hang) around 2% of the time if the race is
+ // present.
+
+ // Ensure enough Ps to actually run everything in parallel. Though on
+ // <4 core machines, we are still at the whim of the kernel scheduler.
+ runtime.GOMAXPROCS(4)
+
+ go func() {
+ // Stop the world; race with LockOSThread below.
+ var m runtime.MemStats
+ for {
+ runtime.ReadMemStats(&m)
+ }
+ }()
+
+ // Try to synchronize both LockOSThreads.
+ start := time.Now().Add(10 * time.Millisecond)
+
+ var wg sync.WaitGroup
+ wg.Add(2)
+
+ for i := 0; i < 2; i++ {
+ go func() {
+ for time.Now().Before(start) {
+ }
+
+ // Add work to the local runq to trigger early startm
+ // in handoffp.
+ go func() {}()
+
+ runtime.LockOSThread()
+ runtime.Gosched() // add a preemption point.
+ wg.Done()
+ }()
+ }
+
+ wg.Wait()
+ // If both LockOSThreads completed then we did not hit the race.
+ println("OK")
+}
diff --git a/src/runtime/testdata/testprog/numcpu_freebsd.go b/src/runtime/testdata/testprog/numcpu_freebsd.go
index 42ee154883..aff36ec702 100644
--- a/src/runtime/testdata/testprog/numcpu_freebsd.go
+++ b/src/runtime/testdata/testprog/numcpu_freebsd.go
@@ -85,7 +85,13 @@ func getList() ([]string, error) {
if err != nil {
return nil, fmt.Errorf("fail to execute '%s': %s", cmdline, err)
}
- pos := bytes.IndexRune(output, ':')
+ pos := bytes.IndexRune(output, '\n')
+ if pos == -1 {
+ return nil, fmt.Errorf("invalid output from '%s', '\\n' not found: %s", cmdline, output)
+ }
+ output = output[0:pos]
+
+ pos = bytes.IndexRune(output, ':')
if pos == -1 {
return nil, fmt.Errorf("invalid output from '%s', ':' not found: %s", cmdline, output)
}
diff --git a/src/runtime/testdata/testprogcgo/eintr.go b/src/runtime/testdata/testprogcgo/eintr.go
new file mode 100644
index 0000000000..791ff1bedc
--- /dev/null
+++ b/src/runtime/testdata/testprogcgo/eintr.go
@@ -0,0 +1,246 @@
+// Copyright 2020 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 !plan9,!windows
+
+package main
+
+/*
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+
+static int clearRestart(int sig) {
+ struct sigaction sa;
+
+ memset(&sa, 0, sizeof sa);
+ if (sigaction(sig, NULL, &sa) < 0) {
+ return errno;
+ }
+ sa.sa_flags &=~ SA_RESTART;
+ if (sigaction(sig, &sa, NULL) < 0) {
+ return errno;
+ }
+ return 0;
+}
+*/
+import "C"
+
+import (
+ "bytes"
+ "errors"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "log"
+ "net"
+ "os"
+ "os/exec"
+ "sync"
+ "syscall"
+ "time"
+)
+
+func init() {
+ register("EINTR", EINTR)
+ register("Block", Block)
+}
+
+// Test various operations when a signal handler is installed without
+// the SA_RESTART flag. This tests that the os and net APIs handle EINTR.
+func EINTR() {
+ if errno := C.clearRestart(C.int(syscall.SIGURG)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+ if errno := C.clearRestart(C.int(syscall.SIGWINCH)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+ if errno := C.clearRestart(C.int(syscall.SIGCHLD)); errno != 0 {
+ log.Fatal(syscall.Errno(errno))
+ }
+
+ var wg sync.WaitGroup
+ testPipe(&wg)
+ testNet(&wg)
+ testExec(&wg)
+ wg.Wait()
+ fmt.Println("OK")
+}
+
+// spin does CPU bound spinning and allocating for a millisecond,
+// to get a SIGURG.
+//go:noinline
+func spin() (float64, []byte) {
+ stop := time.Now().Add(time.Millisecond)
+ r1 := 0.0
+ r2 := make([]byte, 200)
+ for time.Now().Before(stop) {
+ for i := 1; i < 1e6; i++ {
+ r1 += r1 / float64(i)
+ r2 = append(r2, bytes.Repeat([]byte{byte(i)}, 100)...)
+ r2 = r2[100:]
+ }
+ }
+ return r1, r2
+}
+
+// winch sends a few SIGWINCH signals to the process.
+func winch() {
+ ticker := time.NewTicker(100 * time.Microsecond)
+ defer ticker.Stop()
+ pid := syscall.Getpid()
+ for n := 10; n > 0; n-- {
+ syscall.Kill(pid, syscall.SIGWINCH)
+ <-ticker.C
+ }
+}
+
+// sendSomeSignals triggers a few SIGURG and SIGWINCH signals.
+func sendSomeSignals() {
+ done := make(chan struct{})
+ go func() {
+ spin()
+ close(done)
+ }()
+ winch()
+ <-done
+}
+
+// testPipe tests pipe operations.
+func testPipe(wg *sync.WaitGroup) {
+ r, w, err := os.Pipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := syscall.SetNonblock(int(r.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ if err := syscall.SetNonblock(int(w.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ defer w.Close()
+ // Spin before calling Write so that the first ReadFull
+ // in the other goroutine will likely be interrupted
+ // by a signal.
+ sendSomeSignals()
+ // This Write will likely be interrupted by a signal
+ // as the other goroutine spins in the middle of reading.
+ // We write enough data that we should always fill the
+ // pipe buffer and need multiple write system calls.
+ if _, err := w.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
+ log.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ defer r.Close()
+ b := make([]byte, 1<<20)
+ // This ReadFull will likely be interrupted by a signal,
+ // as the other goroutine spins before writing anything.
+ if _, err := io.ReadFull(r, b); err != nil {
+ log.Fatal(err)
+ }
+ // Spin after reading half the data so that the Write
+ // in the other goroutine will likely be interrupted
+ // before it completes.
+ sendSomeSignals()
+ if _, err := io.ReadFull(r, b); err != nil {
+ log.Fatal(err)
+ }
+ }()
+}
+
+// testNet tests network operations.
+func testNet(wg *sync.WaitGroup) {
+ ln, err := net.Listen("tcp4", "127.0.0.1:0")
+ if err != nil {
+ if errors.Is(err, syscall.EAFNOSUPPORT) || errors.Is(err, syscall.EPROTONOSUPPORT) {
+ return
+ }
+ log.Fatal(err)
+ }
+ wg.Add(2)
+ go func() {
+ defer wg.Done()
+ defer ln.Close()
+ c, err := ln.Accept()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer c.Close()
+ cf, err := c.(*net.TCPConn).File()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer cf.Close()
+ if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ // See comments in testPipe.
+ sendSomeSignals()
+ if _, err := cf.Write(bytes.Repeat([]byte{0}, 2<<20)); err != nil {
+ log.Fatal(err)
+ }
+ }()
+ go func() {
+ defer wg.Done()
+ sendSomeSignals()
+ c, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer c.Close()
+ cf, err := c.(*net.TCPConn).File()
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer cf.Close()
+ if err := syscall.SetNonblock(int(cf.Fd()), false); err != nil {
+ log.Fatal(err)
+ }
+ // See comments in testPipe.
+ b := make([]byte, 1<<20)
+ if _, err := io.ReadFull(cf, b); err != nil {
+ log.Fatal(err)
+ }
+ sendSomeSignals()
+ if _, err := io.ReadFull(cf, b); err != nil {
+ log.Fatal(err)
+ }
+ }()
+}
+
+func testExec(wg *sync.WaitGroup) {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ cmd := exec.Command(os.Args[0], "Block")
+ stdin, err := cmd.StdinPipe()
+ if err != nil {
+ log.Fatal(err)
+ }
+ cmd.Stderr = new(bytes.Buffer)
+ cmd.Stdout = cmd.Stderr
+ if err := cmd.Start(); err != nil {
+ log.Fatal(err)
+ }
+
+ go func() {
+ sendSomeSignals()
+ stdin.Close()
+ }()
+
+ if err := cmd.Wait(); err != nil {
+ log.Fatalf("%v:\n%s", err, cmd.Stdout)
+ }
+ }()
+}
+
+// Block blocks until stdin is closed.
+func Block() {
+ io.Copy(ioutil.Discard, os.Stdin)
+}
diff --git a/src/runtime/trace.go b/src/runtime/trace.go
index 33062daa46..169b650eb4 100644
--- a/src/runtime/trace.go
+++ b/src/runtime/trace.go
@@ -187,6 +187,9 @@ func StartTrace() error {
// paired with an end).
stopTheWorldGC("start tracing")
+ // Prevent sysmon from running any code that could generate events.
+ lock(&sched.sysmonlock)
+
// We are in stop-the-world, but syscalls can finish and write to trace concurrently.
// Exitsyscall could check trace.enabled long before and then suddenly wake up
// and decide to write to trace at a random point in time.
@@ -196,6 +199,7 @@ func StartTrace() error {
if trace.enabled || trace.shutdown {
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
startTheWorldGC()
return errorString("tracing is already enabled")
}
@@ -267,6 +271,8 @@ func StartTrace() error {
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
+
startTheWorldGC()
return nil
}
@@ -279,10 +285,14 @@ func StopTrace() {
stopTheWorldGC("stop tracing")
// See the comment in StartTrace.
+ lock(&sched.sysmonlock)
+
+ // See the comment in StartTrace.
lock(&trace.bufLock)
if !trace.enabled {
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
startTheWorldGC()
return
}
@@ -320,6 +330,8 @@ func StopTrace() {
trace.shutdown = true
unlock(&trace.bufLock)
+ unlock(&sched.sysmonlock)
+
startTheWorldGC()
// The world is started but we've set trace.shutdown, so new tracing can't start.
diff --git a/src/runtime/trace/trace.go b/src/runtime/trace/trace.go
index 7f9d72a846..b34aef03c5 100644
--- a/src/runtime/trace/trace.go
+++ b/src/runtime/trace/trace.go
@@ -19,7 +19,7 @@
// command runs the test in the current directory and writes the trace
// file (trace.out).
//
-// go test -trace=test.out
+// go test -trace=trace.out
//
// This runtime/trace package provides APIs to add equivalent tracing
// support to a standalone program. See the Example that demonstrates
diff --git a/src/runtime/trace/trace_stack_test.go b/src/runtime/trace/trace_stack_test.go
index e3608c687f..cfc0419b72 100644
--- a/src/runtime/trace/trace_stack_test.go
+++ b/src/runtime/trace/trace_stack_test.go
@@ -252,6 +252,7 @@ func TestTraceSymbolize(t *testing.T) {
{trace.EvGoSysCall, []frame{
{"syscall.read", 0},
{"syscall.Read", 0},
+ {"internal/poll.ignoringEINTR", 0},
{"internal/poll.(*FD).Read", 0},
{"os.(*File).read", 0},
{"os.(*File).Read", 0},
diff --git a/src/runtime/vlop_386.s b/src/runtime/vlop_386.s
index 3387c519c8..b478ff89c0 100644
--- a/src/runtime/vlop_386.s
+++ b/src/runtime/vlop_386.s
@@ -1,5 +1,5 @@
// Inferno's libkern/vlop-386.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlop-386.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlop-386.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/vlop_arm.s b/src/runtime/vlop_arm.s
index 3f28f03c48..9e19938565 100644
--- a/src/runtime/vlop_arm.s
+++ b/src/runtime/vlop_arm.s
@@ -1,5 +1,5 @@
// Inferno's libkern/vlop-arm.s
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlop-arm.s
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlop-arm.s
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/runtime/vlrt.go b/src/runtime/vlrt.go
index 87370f870d..38e0b32801 100644
--- a/src/runtime/vlrt.go
+++ b/src/runtime/vlrt.go
@@ -1,5 +1,5 @@
// Inferno's libkern/vlrt-arm.c
-// https://bitbucket.org/inferno-os/inferno-os/src/default/libkern/vlrt-arm.c
+// https://bitbucket.org/inferno-os/inferno-os/src/master/libkern/vlrt-arm.c
//
// Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
// Revisions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
diff --git a/src/strconv/atoc.go b/src/strconv/atoc.go
new file mode 100644
index 0000000000..55b7c23ee7
--- /dev/null
+++ b/src/strconv/atoc.go
@@ -0,0 +1,105 @@
+// Copyright 2020 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 strconv
+
+const fnParseComplex = "ParseComplex"
+
+// convErr splits an error returned by parseFloatPrefix
+// into a syntax or range error for ParseComplex.
+func convErr(err error, s string) (syntax, range_ error) {
+ if x, ok := err.(*NumError); ok {
+ x.Func = fnParseComplex
+ x.Num = s
+ if x.Err == ErrRange {
+ return nil, x
+ }
+ }
+ return err, nil
+}
+
+// ParseComplex converts the string s to a complex number
+// with the precision specified by bitSize: 64 for complex64, or 128 for complex128.
+// When bitSize=64, the result still has type complex128, but it will be
+// convertible to complex64 without changing its value.
+//
+// The number represented by s must be of the form N, Ni, or N±Ni, where N stands
+// for a floating-point number as recognized by ParseFloat, and i is the imaginary
+// component. If the second N is unsigned, a + sign is required between the two components
+// as indicated by the ±. If the second N is NaN, only a + sign is accepted.
+// The form may be parenthesized and cannot contain any spaces.
+// The resulting complex number consists of the two components converted by ParseFloat.
+//
+// The errors that ParseComplex returns have concrete type *NumError
+// and include err.Num = s.
+//
+// If s is not syntactically well-formed, ParseComplex returns err.Err = ErrSyntax.
+//
+// If s is syntactically well-formed but either component is more than 1/2 ULP
+// away from the largest floating point number of the given component's size,
+// ParseComplex returns err.Err = ErrRange and c = ±Inf for the respective component.
+func ParseComplex(s string, bitSize int) (complex128, error) {
+ size := 128
+ if bitSize == 64 {
+ size = 32 // complex64 uses float32 parts
+ }
+
+ orig := s
+
+ // Remove parentheses, if any.
+ if len(s) >= 2 && s[0] == '(' && s[len(s)-1] == ')' {
+ s = s[1 : len(s)-1]
+ }
+
+ var pending error // pending range error, or nil
+
+ // Read real part (possibly imaginary part if followed by 'i').
+ re, n, err := parseFloatPrefix(s, size)
+ if err != nil {
+ err, pending = convErr(err, orig)
+ if err != nil {
+ return 0, err
+ }
+ }
+ s = s[n:]
+
+ // If we have nothing left, we're done.
+ if len(s) == 0 {
+ return complex(re, 0), pending
+ }
+
+ // Otherwise, look at the next character.
+ switch s[0] {
+ case '+':
+ // Consume the '+' to avoid an error if we have "+NaNi", but
+ // do this only if we don't have a "++" (don't hide that error).
+ if len(s) > 1 && s[1] != '+' {
+ s = s[1:]
+ }
+ case '-':
+ // ok
+ case 'i':
+ // If 'i' is the last character, we only have an imaginary part.
+ if len(s) == 1 {
+ return complex(0, re), pending
+ }
+ fallthrough
+ default:
+ return 0, syntaxError(fnParseComplex, orig)
+ }
+
+ // Read imaginary part.
+ im, n, err := parseFloatPrefix(s, size)
+ if err != nil {
+ err, pending = convErr(err, orig)
+ if err != nil {
+ return 0, err
+ }
+ }
+ s = s[n:]
+ if s != "i" {
+ return 0, syntaxError(fnParseComplex, orig)
+ }
+ return complex(re, im), pending
+}
diff --git a/src/strconv/atoc_test.go b/src/strconv/atoc_test.go
new file mode 100644
index 0000000000..3aa421dd03
--- /dev/null
+++ b/src/strconv/atoc_test.go
@@ -0,0 +1,202 @@
+// Copyright 2020 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 strconv_test
+
+import (
+ "math"
+ "math/cmplx"
+ "reflect"
+ . "strconv"
+ "testing"
+)
+
+var (
+ infp0 = complex(math.Inf(+1), 0)
+ infm0 = complex(math.Inf(-1), 0)
+ inf0p = complex(0, math.Inf(+1))
+ inf0m = complex(0, math.Inf(-1))
+
+ infpp = complex(math.Inf(+1), math.Inf(+1))
+ infpm = complex(math.Inf(+1), math.Inf(-1))
+ infmp = complex(math.Inf(-1), math.Inf(+1))
+ infmm = complex(math.Inf(-1), math.Inf(-1))
+)
+
+type atocTest struct {
+ in string
+ out complex128
+ err error
+}
+
+func TestParseComplex(t *testing.T) {
+ tests := []atocTest{
+ // Clearly invalid
+ {"", 0, ErrSyntax},
+ {" ", 0, ErrSyntax},
+ {"(", 0, ErrSyntax},
+ {")", 0, ErrSyntax},
+ {"i", 0, ErrSyntax},
+ {"+i", 0, ErrSyntax},
+ {"-i", 0, ErrSyntax},
+ {"1I", 0, ErrSyntax},
+ {"10 + 5i", 0, ErrSyntax},
+ {"3+", 0, ErrSyntax},
+ {"3+5", 0, ErrSyntax},
+ {"3+5+5i", 0, ErrSyntax},
+
+ // Parentheses
+ {"()", 0, ErrSyntax},
+ {"(i)", 0, ErrSyntax},
+ {"(0)", 0, nil},
+ {"(1i)", 1i, nil},
+ {"(3.0+5.5i)", 3.0 + 5.5i, nil},
+ {"(1)+1i", 0, ErrSyntax},
+ {"(3.0+5.5i", 0, ErrSyntax},
+ {"3.0+5.5i)", 0, ErrSyntax},
+
+ // NaNs
+ {"NaN", complex(math.NaN(), 0), nil},
+ {"NANi", complex(0, math.NaN()), nil},
+ {"nan+nAni", complex(math.NaN(), math.NaN()), nil},
+ {"+NaN", 0, ErrSyntax},
+ {"-NaN", 0, ErrSyntax},
+ {"NaN-NaNi", 0, ErrSyntax},
+
+ // Infs
+ {"Inf", infp0, nil},
+ {"+inf", infp0, nil},
+ {"-inf", infm0, nil},
+ {"Infinity", infp0, nil},
+ {"+INFINITY", infp0, nil},
+ {"-infinity", infm0, nil},
+ {"+infi", inf0p, nil},
+ {"0-infinityi", inf0m, nil},
+ {"Inf+Infi", infpp, nil},
+ {"+Inf-Infi", infpm, nil},
+ {"-Infinity+Infi", infmp, nil},
+ {"inf-inf", 0, ErrSyntax},
+
+ // Zeros
+ {"0", 0, nil},
+ {"0i", 0, nil},
+ {"-0.0i", 0, nil},
+ {"0+0.0i", 0, nil},
+ {"0e+0i", 0, nil},
+ {"0e-0+0i", 0, nil},
+ {"-0.0-0.0i", 0, nil},
+ {"0e+012345", 0, nil},
+ {"0x0p+012345i", 0, nil},
+ {"0x0.00p-012345i", 0, nil},
+ {"+0e-0+0e-0i", 0, nil},
+ {"0e+0+0e+0i", 0, nil},
+ {"-0e+0-0e+0i", 0, nil},
+
+ // Regular non-zeroes
+ {"0.1", 0.1, nil},
+ {"0.1i", 0 + 0.1i, nil},
+ {"0.123", 0.123, nil},
+ {"0.123i", 0 + 0.123i, nil},
+ {"0.123+0.123i", 0.123 + 0.123i, nil},
+ {"99", 99, nil},
+ {"+99", 99, nil},
+ {"-99", -99, nil},
+ {"+1i", 1i, nil},
+ {"-1i", -1i, nil},
+ {"+3+1i", 3 + 1i, nil},
+ {"30+3i", 30 + 3i, nil},
+ {"+3e+3-3e+3i", 3e+3 - 3e+3i, nil},
+ {"+3e+3+3e+3i", 3e+3 + 3e+3i, nil},
+ {"+3e+3+3e+3i+", 0, ErrSyntax},
+
+ // Separators
+ {"0.1", 0.1, nil},
+ {"0.1i", 0 + 0.1i, nil},
+ {"0.1_2_3", 0.123, nil},
+ {"+0x_3p3i", 0x3p3i, nil},
+ {"0_0+0x_0p0i", 0, nil},
+ {"0x_10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
+ {"+0x_1_0.3p-8+0x_3_0p3i", 0x10.3p-8 + 0x30p3i, nil},
+ {"0x1_0.3p+8-0x_3p3i", 0x10.3p+8 - 0x3p3i, nil},
+
+ // Hexadecimals
+ {"0x10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
+ {"+0x10.3p-8+0x3p3i", 0x10.3p-8 + 0x3p3i, nil},
+ {"0x10.3p+8-0x3p3i", 0x10.3p+8 - 0x3p3i, nil},
+ {"0x1p0", 1, nil},
+ {"0x1p1", 2, nil},
+ {"0x1p-1", 0.5, nil},
+ {"0x1ep-1", 15, nil},
+ {"-0x1ep-1", -15, nil},
+ {"-0x2p3", -16, nil},
+ {"0x1e2", 0, ErrSyntax},
+ {"1p2", 0, ErrSyntax},
+ {"0x1e2i", 0, ErrSyntax},
+
+ // ErrRange
+ // next float64 - too large
+ {"+0x1p1024", infp0, ErrRange},
+ {"-0x1p1024", infm0, ErrRange},
+ {"+0x1p1024i", inf0p, ErrRange},
+ {"-0x1p1024i", inf0m, ErrRange},
+ {"+0x1p1024+0x1p1024i", infpp, ErrRange},
+ {"+0x1p1024-0x1p1024i", infpm, ErrRange},
+ {"-0x1p1024+0x1p1024i", infmp, ErrRange},
+ {"-0x1p1024-0x1p1024i", infmm, ErrRange},
+ // the border is ...158079
+ // borderline - okay
+ {"+0x1.fffffffffffff7fffp1023+0x1.fffffffffffff7fffp1023i", 1.7976931348623157e+308 + 1.7976931348623157e+308i, nil},
+ {"+0x1.fffffffffffff7fffp1023-0x1.fffffffffffff7fffp1023i", 1.7976931348623157e+308 - 1.7976931348623157e+308i, nil},
+ {"-0x1.fffffffffffff7fffp1023+0x1.fffffffffffff7fffp1023i", -1.7976931348623157e+308 + 1.7976931348623157e+308i, nil},
+ {"-0x1.fffffffffffff7fffp1023-0x1.fffffffffffff7fffp1023i", -1.7976931348623157e+308 - 1.7976931348623157e+308i, nil},
+ // borderline - too large
+ {"+0x1.fffffffffffff8p1023", infp0, ErrRange},
+ {"-0x1fffffffffffff.8p+971", infm0, ErrRange},
+ {"+0x1.fffffffffffff8p1023i", inf0p, ErrRange},
+ {"-0x1fffffffffffff.8p+971i", inf0m, ErrRange},
+ {"+0x1.fffffffffffff8p1023+0x1.fffffffffffff8p1023i", infpp, ErrRange},
+ {"+0x1.fffffffffffff8p1023-0x1.fffffffffffff8p1023i", infpm, ErrRange},
+ {"-0x1fffffffffffff.8p+971+0x1fffffffffffff.8p+971i", infmp, ErrRange},
+ {"-0x1fffffffffffff8p+967-0x1fffffffffffff8p+967i", infmm, ErrRange},
+ // a little too large
+ {"1e308+1e308i", 1e+308 + 1e+308i, nil},
+ {"2e308+2e308i", infpp, ErrRange},
+ {"1e309+1e309i", infpp, ErrRange},
+ {"0x1p1025+0x1p1025i", infpp, ErrRange},
+ {"2e308", infp0, ErrRange},
+ {"1e309", infp0, ErrRange},
+ {"0x1p1025", infp0, ErrRange},
+ {"2e308i", inf0p, ErrRange},
+ {"1e309i", inf0p, ErrRange},
+ {"0x1p1025i", inf0p, ErrRange},
+ // way too large
+ {"+1e310+1e310i", infpp, ErrRange},
+ {"+1e310-1e310i", infpm, ErrRange},
+ {"-1e310+1e310i", infmp, ErrRange},
+ {"-1e310-1e310i", infmm, ErrRange},
+ // under/overflow exponent
+ {"1e-4294967296", 0, nil},
+ {"1e-4294967296i", 0, nil},
+ {"1e-4294967296+1i", 1i, nil},
+ {"1+1e-4294967296i", 1, nil},
+ {"1e-4294967296+1e-4294967296i", 0, nil},
+ {"1e+4294967296", infp0, ErrRange},
+ {"1e+4294967296i", inf0p, ErrRange},
+ {"1e+4294967296+1e+4294967296i", infpp, ErrRange},
+ {"1e+4294967296-1e+4294967296i", infpm, ErrRange},
+ }
+ for i := range tests {
+ test := &tests[i]
+ if test.err != nil {
+ test.err = &NumError{Func: "ParseComplex", Num: test.in, Err: test.err}
+ }
+ got, err := ParseComplex(test.in, 128)
+ if !reflect.DeepEqual(err, test.err) {
+ t.Fatalf("ParseComplex(%q, 128) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+ }
+ if !(cmplx.IsNaN(test.out) && cmplx.IsNaN(got)) && got != test.out {
+ t.Fatalf("ParseComplex(%q, 128) = %v, %v; want %v, %v", test.in, got, err, test.out, test.err)
+ }
+ }
+}
diff --git a/src/strconv/atof.go b/src/strconv/atof.go
index 28ad094080..901f27afff 100644
--- a/src/strconv/atof.go
+++ b/src/strconv/atof.go
@@ -300,7 +300,7 @@ loop:
exp = dp - ndMant
}
- if underscores && !underscoreOK(s) {
+ if underscores && !underscoreOK(s[:i]) {
return
}
@@ -677,8 +677,8 @@ func atof64(s string) (f float64, n int, err error) {
// away from the largest floating point number of the given size,
// ParseFloat returns f = ±Inf, err.Err = ErrRange.
//
-// ParseFloat recognizes the strings "NaN", "+Inf", and "-Inf" as their
-// respective special floating point values. It ignores case when matching.
+// ParseFloat recognizes the strings "NaN", and the (possibly signed) strings "Inf" and "Infinity"
+// as their respective special floating point values. It ignores case when matching.
func ParseFloat(s string, bitSize int) (float64, error) {
f, n, err := parseFloatPrefix(s, bitSize)
if err == nil && n != len(s) {
diff --git a/src/strconv/atof_test.go b/src/strconv/atof_test.go
index c30cb2e0fe..545d989c41 100644
--- a/src/strconv/atof_test.go
+++ b/src/strconv/atof_test.go
@@ -480,7 +480,7 @@ func initAtofOnce() {
}
func TestParseFloatPrefix(t *testing.T) {
- for i := 0; i < len(atoftests); i++ {
+ for i := range atoftests {
test := &atoftests[i]
if test.err != nil {
continue
diff --git a/src/strconv/atoi.go b/src/strconv/atoi.go
index 0b82fb0908..f6c4efaef6 100644
--- a/src/strconv/atoi.go
+++ b/src/strconv/atoi.go
@@ -22,7 +22,7 @@ var ErrSyntax = errors.New("invalid syntax")
// A NumError records a failed conversion.
type NumError struct {
- Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat)
+ Func string // the failing function (ParseBool, ParseInt, ParseUint, ParseFloat, ParseComplex)
Num string // the input
Err error // the reason the conversion failed (e.g. ErrRange, ErrSyntax, etc.)
}
diff --git a/src/strconv/ctoa.go b/src/strconv/ctoa.go
new file mode 100644
index 0000000000..c16a2e579c
--- /dev/null
+++ b/src/strconv/ctoa.go
@@ -0,0 +1,27 @@
+// Copyright 2020 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 strconv
+
+// FormatComplex converts the complex number c to a string of the
+// form (a+bi) where a and b are the real and imaginary parts,
+// formatted according to the format fmt and precision prec.
+//
+// The format fmt and precision prec have the same meaning as in FormatFloat.
+// It rounds the result assuming that the original was obtained from a complex
+// value of bitSize bits, which must be 64 for complex64 and 128 for complex128.
+func FormatComplex(c complex128, fmt byte, prec, bitSize int) string {
+ if bitSize != 64 && bitSize != 128 {
+ panic("invalid bitSize")
+ }
+ bitSize >>= 1 // complex64 uses float32 internally
+
+ // Check if imaginary part has a sign. If not, add one.
+ im := FormatFloat(imag(c), fmt, prec, bitSize)
+ if im[0] != '+' && im[0] != '-' {
+ im = "+" + im
+ }
+
+ return "(" + FormatFloat(real(c), fmt, prec, bitSize) + im + "i)"
+}
diff --git a/src/syscall/asm_openbsd_arm.s b/src/syscall/asm_openbsd_arm.s
index 9279ed960f..26fd791fda 100644
--- a/src/syscall/asm_openbsd_arm.s
+++ b/src/syscall/asm_openbsd_arm.s
@@ -15,13 +15,20 @@
// func RawSyscall(trap int32, a1, a2, a3 int32) (r1, r2, err int32);
// func RawSyscall6(trap int32, a1, a2, a3, a4, a5, a6 int32) (r1, r2, err int32);
+// See comment in runtime/sys_openbsd_arm.s re this construction.
+#define NOOP MOVW R0, R0
+#define INVOKE_SYSCALL \
+ SWI $0; \
+ NOOP; \
+ NOOP
+
TEXT ·Syscall(SB),NOSPLIT,$0-28
BL runtime·entersyscall(SB)
MOVW trap+0(FP), R12 // syscall number
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
- SWI $0
+ INVOKE_SYSCALL
MOVW $0, R2
BCS error
MOVW R0, r1+16(FP) // ret 1
@@ -46,7 +53,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-40
MOVW a4+16(FP), R3 // arg 4
MOVW R13, R4
MOVW $a5+20(FP), R13 // arg 5 to arg 6 are passed on stack
- SWI $0
+ INVOKE_SYSCALL
MOVW R4, R13
MOVW $0, R2
BCS error6
@@ -72,7 +79,7 @@ TEXT ·Syscall9(SB),NOSPLIT,$0-52
MOVW a4+16(FP), R3 // arg 4
MOVW R13, R4
MOVW $a5+20(FP), R13 // arg 5 to arg 9 are passed on stack
- SWI $0
+ INVOKE_SYSCALL
MOVW R4, R13
MOVW $0, R2
BCS error9
@@ -94,7 +101,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-28
MOVW a1+4(FP), R0 // arg 1
MOVW a2+8(FP), R1 // arg 2
MOVW a3+12(FP), R2 // arg 3
- SWI $0
+ INVOKE_SYSCALL
MOVW $0, R2
BCS errorr
MOVW R0, r1+16(FP) // ret 1
@@ -116,7 +123,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-40
MOVW a4+16(FP), R3 // arg 4
MOVW R13, R4
MOVW $a5+20(FP), R13 // arg 5 to arg 6 are passed on stack
- SWI $0
+ INVOKE_SYSCALL
MOVW R4, R13
MOVW $0, R2
BCS errorr6
diff --git a/src/syscall/asm_openbsd_arm64.s b/src/syscall/asm_openbsd_arm64.s
index 16be5fb854..dcbed10cbe 100644
--- a/src/syscall/asm_openbsd_arm64.s
+++ b/src/syscall/asm_openbsd_arm64.s
@@ -4,6 +4,12 @@
#include "textflag.h"
+// See comment in runtime/sys_openbsd_arm64.s re this construction.
+#define INVOKE_SYSCALL \
+ SVC; \
+ NOOP; \
+ NOOP
+
// func Syscall(trap int64, a1, a2, a3 int64) (r1, r2, err int64);
TEXT ·Syscall(SB),NOSPLIT,$0-56
BL runtime·entersyscall(SB)
@@ -14,7 +20,7 @@ TEXT ·Syscall(SB),NOSPLIT,$0-56
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall number
- SVC
+ INVOKE_SYSCALL
BCC ok
MOVD $-1, R4
MOVD R4, r1+32(FP) // r1
@@ -38,7 +44,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-80
MOVD a5+40(FP), R4
MOVD a6+48(FP), R5
MOVD trap+0(FP), R8 // syscall number
- SVC
+ INVOKE_SYSCALL
BCC ok
MOVD $-1, R4
MOVD R4, r1+56(FP) // r1
@@ -66,7 +72,7 @@ TEXT ·Syscall9(SB),NOSPLIT,$0-104
MOVD a9+72(FP), R8 // on stack
MOVD R8, 8(RSP)
MOVD num+0(FP), R8 // syscall number
- SVC
+ INVOKE_SYSCALL
BCC ok
MOVD $-1, R4
MOVD R4, r1+80(FP) // r1
@@ -89,7 +95,7 @@ TEXT ·RawSyscall(SB),NOSPLIT,$0-56
MOVD $0, R4
MOVD $0, R5
MOVD trap+0(FP), R8 // syscall number
- SVC
+ INVOKE_SYSCALL
BCC ok
MOVD $-1, R4
MOVD R4, r1+32(FP) // r1
@@ -110,7 +116,7 @@ TEXT ·RawSyscall6(SB),NOSPLIT,$0-80
MOVD a5+40(FP), R4
MOVD a6+48(FP), R5
MOVD trap+0(FP), R8 // syscall number
- SVC
+ INVOKE_SYSCALL
BCC ok
MOVD $-1, R4
MOVD R4, r1+56(FP) // r1
diff --git a/src/syscall/dll_windows.go b/src/syscall/dll_windows.go
index 75bc372c3d..c54feec56a 100644
--- a/src/syscall/dll_windows.go
+++ b/src/syscall/dll_windows.go
@@ -21,6 +21,7 @@ type DLLError struct {
func (e *DLLError) Error() string { return e.Msg }
// Implemented in ../runtime/syscall_windows.go.
+
func Syscall(trap, nargs, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
func Syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
func Syscall9(trap, nargs, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
@@ -162,7 +163,15 @@ func (p *Proc) Addr() uintptr {
// The returned error is always non-nil, constructed from the result of GetLastError.
// Callers must inspect the primary return value to decide whether an error occurred
// (according to the semantics of the specific function being called) before consulting
-// the error. The error will be guaranteed to contain syscall.Errno.
+// the error. The error always has type syscall.Errno.
+//
+// On amd64, Call can pass and return floating-point values. To pass
+// an argument x with C type "float", use
+// uintptr(math.Float32bits(x)). To pass an argument with C type
+// "double", use uintptr(math.Float64bits(x)). Floating-point return
+// values are returned in r2. The return value for C type "float" is
+// math.Float32frombits(uint32(r2)). For C type "double", it is
+// math.Float64frombits(uint64(r2)).
func (p *Proc) Call(a ...uintptr) (r1, r2 uintptr, lastErr error) {
switch len(a) {
case 0:
diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go
deleted file mode 100644
index e403a25e31..0000000000
--- a/src/syscall/env_plan9.go
+++ /dev/null
@@ -1,122 +0,0 @@
-// Copyright 2011 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-// Plan 9 environment variables.
-
-package syscall
-
-import (
- "errors"
-)
-
-var (
- errZeroLengthKey = errors.New("zero length key")
- errShortWrite = errors.New("i/o count too small")
-)
-
-func readenv(key string) (string, error) {
- fd, err := open("/env/"+key, O_RDONLY)
- if err != nil {
- return "", err
- }
- defer Close(fd)
- l, _ := Seek(fd, 0, 2)
- Seek(fd, 0, 0)
- buf := make([]byte, l)
- n, err := Read(fd, buf)
- if err != nil {
- return "", err
- }
- if n > 0 && buf[n-1] == 0 {
- buf = buf[:n-1]
- }
- return string(buf), nil
-}
-
-func writeenv(key, value string) error {
- fd, err := create("/env/"+key, O_RDWR, 0666)
- if err != nil {
- return err
- }
- defer Close(fd)
- b := []byte(value)
- n, err := Write(fd, b)
- if err != nil {
- return err
- }
- if n != len(b) {
- return errShortWrite
- }
- return nil
-}
-
-func Getenv(key string) (value string, found bool) {
- if len(key) == 0 {
- return "", false
- }
- v, err := readenv(key)
- if err != nil {
- return "", false
- }
- return v, true
-}
-
-func Setenv(key, value string) error {
- if len(key) == 0 {
- return errZeroLengthKey
- }
- err := writeenv(key, value)
- if err != nil {
- return err
- }
- return nil
-}
-
-func Clearenv() {
- // Creating a new environment group using rfork(RFCENVG) can race
- // with access to files in /env (e.g. from Setenv or Getenv).
- // Remove all environment variables in current environment group instead.
- fd, err := open("/env", O_RDONLY)
- if err != nil {
- return
- }
- defer Close(fd)
- files, err := readdirnames(fd)
- if err != nil {
- return
- }
- for _, key := range files {
- Remove("/env/" + key)
- }
-}
-
-func Unsetenv(key string) error {
- if len(key) == 0 {
- return errZeroLengthKey
- }
- Remove("/env/" + key)
- return nil
-}
-
-func Environ() []string {
- fd, err := open("/env", O_RDONLY)
- if err != nil {
- return nil
- }
- defer Close(fd)
- files, err := readdirnames(fd)
- if err != nil {
- return nil
- }
- ret := make([]string, 0, len(files))
-
- for _, key := range files {
- v, err := readenv(key)
- if err != nil {
- continue
- }
- ret = append(ret, key+"="+v)
- }
- return ret
-}
diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go
index e80a3ff1c9..a4bb28cc45 100644
--- a/src/syscall/env_unix.go
+++ b/src/syscall/env_unix.go
@@ -2,13 +2,16 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris
+// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9
// Unix environment variables.
package syscall
-import "sync"
+import (
+ "runtime"
+ "sync"
+)
var (
// envOnce guards initialization by copyenv, which populates env.
@@ -100,9 +103,12 @@ func Setenv(key, value string) error {
return EINVAL
}
}
- for i := 0; i < len(value); i++ {
- if value[i] == 0 {
- return EINVAL
+ // On Plan 9, null is used as a separator, eg in $path.
+ if runtime.GOOS != "plan9" {
+ for i := 0; i < len(value); i++ {
+ if value[i] == 0 {
+ return EINVAL
+ }
}
}
diff --git a/src/syscall/exec_linux_test.go b/src/syscall/exec_linux_test.go
index b7a8df21b5..b79dee7525 100644
--- a/src/syscall/exec_linux_test.go
+++ b/src/syscall/exec_linux_test.go
@@ -355,7 +355,7 @@ func TestUnshareMountNameSpace(t *testing.T) {
}
cmd := exec.Command(os.Args[0], "-test.run=TestUnshareMountNameSpaceHelper", d)
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.SysProcAttr = &syscall.SysProcAttr{Unshareflags: syscall.CLONE_NEWNS}
o, err := cmd.CombinedOutput()
@@ -406,7 +406,7 @@ func TestUnshareMountNameSpaceChroot(t *testing.T) {
}
cmd = exec.Command("/syscall.test", "-test.run=TestUnshareMountNameSpaceHelper", "/")
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.SysProcAttr = &syscall.SysProcAttr{Chroot: d, Unshareflags: syscall.CLONE_NEWNS}
o, err := cmd.CombinedOutput()
@@ -621,7 +621,7 @@ func testAmbientCaps(t *testing.T, userns bool) {
}
cmd := exec.Command(f.Name(), "-test.run=TestAmbientCapsHelper")
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
cmd.SysProcAttr = &syscall.SysProcAttr{
diff --git a/src/syscall/exec_unix.go b/src/syscall/exec_unix.go
index 0345af44f9..cb08b7084c 100644
--- a/src/syscall/exec_unix.go
+++ b/src/syscall/exec_unix.go
@@ -217,7 +217,12 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err error)
// Read child error status from pipe.
Close(p[1])
- n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ for {
+ n, err = readlen(p[0], (*byte)(unsafe.Pointer(&err1)), int(unsafe.Sizeof(err1)))
+ if err != EINTR {
+ break
+ }
+ }
Close(p[0])
if err != nil || n != 0 {
if n == int(unsafe.Sizeof(err1)) {
diff --git a/src/syscall/js/func.go b/src/syscall/js/func.go
index 9e99027e9f..da4cf68774 100644
--- a/src/syscall/js/func.go
+++ b/src/syscall/js/func.go
@@ -39,7 +39,7 @@ type Func struct {
// immediate deadlock. Therefore a blocking function should explicitly start a
// new goroutine.
//
-// Func.Release must be called to free up resources when the function will not be used any more.
+// Func.Release must be called to free up resources when the function will not be invoked any more.
func FuncOf(fn func(this Value, args []Value) interface{}) Func {
funcsMu.Lock()
id := nextFuncID
@@ -54,6 +54,7 @@ func FuncOf(fn func(this Value, args []Value) interface{}) Func {
// Release frees up resources allocated for the function.
// The function must not be invoked after calling Release.
+// It is allowed to call Release while the function is still running.
func (c Func) Release() {
funcsMu.Lock()
delete(funcs, c.id)
diff --git a/src/syscall/js/js_test.go b/src/syscall/js/js_test.go
index fea4c135af..5fc9107d40 100644
--- a/src/syscall/js/js_test.go
+++ b/src/syscall/js/js_test.go
@@ -591,3 +591,14 @@ func BenchmarkDOM(b *testing.B) {
document.Get("body").Call("removeChild", div)
}
}
+
+func TestGlobal(t *testing.T) {
+ ident := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ return args[0]
+ })
+ defer ident.Release()
+
+ if got := ident.Invoke(js.Global()); !got.Equal(js.Global()) {
+ t.Errorf("got %#v, want %#v", got, js.Global())
+ }
+}
diff --git a/src/syscall/syscall_dup2_linux.go b/src/syscall/syscall_dup2_linux.go
new file mode 100644
index 0000000000..f03a923112
--- /dev/null
+++ b/src/syscall/syscall_dup2_linux.go
@@ -0,0 +1,10 @@
+// Copyright 2020 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 !android
+// +build 386 amd64 arm mips mipsle mips64 mips64le ppc64 ppc64le s390x
+
+package syscall
+
+const _SYS_dup = SYS_DUP2
diff --git a/src/syscall/syscall_dup3_linux.go b/src/syscall/syscall_dup3_linux.go
new file mode 100644
index 0000000000..1ebdcb20a2
--- /dev/null
+++ b/src/syscall/syscall_dup3_linux.go
@@ -0,0 +1,9 @@
+// Copyright 2020 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 android arm64 riscv64
+
+package syscall
+
+const _SYS_dup = SYS_DUP3
diff --git a/src/syscall/syscall_linux.go b/src/syscall/syscall_linux.go
index 2eba033d7c..07fe6a6c2b 100644
--- a/src/syscall/syscall_linux.go
+++ b/src/syscall/syscall_linux.go
@@ -35,6 +35,20 @@ func Creat(path string, mode uint32) (fd int, err error) {
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
}
+func isGroupMember(gid int) bool {
+ groups, err := Getgroups()
+ if err != nil {
+ return false
+ }
+
+ for _, g := range groups {
+ if g == gid {
+ return true
+ }
+ }
+ return false
+}
+
//sys faccessat(dirfd int, path string, mode uint32) (err error)
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
@@ -92,7 +106,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
gid = Getgid()
}
- if uint32(gid) == st.Gid {
+ if uint32(gid) == st.Gid || isGroupMember(gid) {
fmode = (st.Mode >> 3) & 7
} else {
fmode = st.Mode & 7
diff --git a/src/syscall/syscall_linux_386.go b/src/syscall/syscall_linux_386.go
index 3c1e6e4218..5076dd97ab 100644
--- a/src/syscall/syscall_linux_386.go
+++ b/src/syscall/syscall_linux_386.go
@@ -9,10 +9,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS32
-)
+const _SYS_setgroups = SYS_SETGROUPS32
func setTimespec(sec, nsec int64) Timespec {
return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
diff --git a/src/syscall/syscall_linux_amd64.go b/src/syscall/syscall_linux_amd64.go
index 0f28b55d47..bf340d9996 100644
--- a/src/syscall/syscall_linux_amd64.go
+++ b/src/syscall/syscall_linux_amd64.go
@@ -4,10 +4,7 @@
package syscall
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
//sys Dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error)
diff --git a/src/syscall/syscall_linux_arm.go b/src/syscall/syscall_linux_arm.go
index d346029a1f..c4c403a400 100644
--- a/src/syscall/syscall_linux_arm.go
+++ b/src/syscall/syscall_linux_arm.go
@@ -6,10 +6,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS32
-)
+const _SYS_setgroups = SYS_SETGROUPS32
func setTimespec(sec, nsec int64) Timespec {
return Timespec{Sec: int32(sec), Nsec: int32(nsec)}
diff --git a/src/syscall/syscall_linux_arm64.go b/src/syscall/syscall_linux_arm64.go
index 1ad9dd8ea3..61014b264a 100644
--- a/src/syscall/syscall_linux_arm64.go
+++ b/src/syscall/syscall_linux_arm64.go
@@ -6,10 +6,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP3
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
func EpollCreate(size int) (fd int, err error) {
if size <= 0 {
diff --git a/src/syscall/syscall_linux_mips64x.go b/src/syscall/syscall_linux_mips64x.go
index 157c32326b..e3683def67 100644
--- a/src/syscall/syscall_linux_mips64x.go
+++ b/src/syscall/syscall_linux_mips64x.go
@@ -7,10 +7,7 @@
package syscall
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
//sys Dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error)
diff --git a/src/syscall/syscall_linux_mipsx.go b/src/syscall/syscall_linux_mipsx.go
index f2fea71aac..cbe2f0233f 100644
--- a/src/syscall/syscall_linux_mipsx.go
+++ b/src/syscall/syscall_linux_mipsx.go
@@ -9,10 +9,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
func Syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
diff --git a/src/syscall/syscall_linux_ppc64x.go b/src/syscall/syscall_linux_ppc64x.go
index 22d6e56010..ba52e5a3ac 100644
--- a/src/syscall/syscall_linux_ppc64x.go
+++ b/src/syscall/syscall_linux_ppc64x.go
@@ -7,10 +7,7 @@
package syscall
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
//sys Dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error)
diff --git a/src/syscall/syscall_linux_riscv64.go b/src/syscall/syscall_linux_riscv64.go
index 61e9c60e70..d54bd38510 100644
--- a/src/syscall/syscall_linux_riscv64.go
+++ b/src/syscall/syscall_linux_riscv64.go
@@ -6,10 +6,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP3
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
func EpollCreate(size int) (fd int, err error) {
if size <= 0 {
diff --git a/src/syscall/syscall_linux_s390x.go b/src/syscall/syscall_linux_s390x.go
index fcedf5909a..80cb1ccc19 100644
--- a/src/syscall/syscall_linux_s390x.go
+++ b/src/syscall/syscall_linux_s390x.go
@@ -6,10 +6,7 @@ package syscall
import "unsafe"
-const (
- _SYS_dup = SYS_DUP2
- _SYS_setgroups = SYS_SETGROUPS
-)
+const _SYS_setgroups = SYS_SETGROUPS
//sys Dup2(oldfd int, newfd int) (err error)
//sysnb EpollCreate(size int) (fd int, err error)
diff --git a/src/syscall/syscall_linux_test.go b/src/syscall/syscall_linux_test.go
index e30a10b870..c5008f2913 100644
--- a/src/syscall/syscall_linux_test.go
+++ b/src/syscall/syscall_linux_test.go
@@ -187,7 +187,7 @@ func TestLinuxDeathSignal(t *testing.T) {
}
cmd := exec.Command(tmpBinary)
- cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
+ cmd.Env = append(os.Environ(), "GO_DEATHSIG_PARENT=1")
chldStdin, err := cmd.StdinPipe()
if err != nil {
t.Fatalf("failed to create new stdin pipe: %v", err)
@@ -225,7 +225,10 @@ func TestLinuxDeathSignal(t *testing.T) {
func deathSignalParent() {
cmd := exec.Command(os.Args[0])
- cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
+ cmd.Env = append(os.Environ(),
+ "GO_DEATHSIG_PARENT=",
+ "GO_DEATHSIG_CHILD=1",
+ )
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout
attrs := syscall.SysProcAttr{
@@ -356,7 +359,7 @@ func TestSyscallNoError(t *testing.T) {
}
cmd := exec.Command(tmpBinary)
- cmd.Env = []string{"GO_SYSCALL_NOERROR=1"}
+ cmd.Env = append(os.Environ(), "GO_SYSCALL_NOERROR=1")
out, err := cmd.CombinedOutput()
if err != nil {
diff --git a/src/syscall/syscall_windows.go b/src/syscall/syscall_windows.go
index 89c0a930cb..f62c00d72f 100644
--- a/src/syscall/syscall_windows.go
+++ b/src/syscall/syscall_windows.go
@@ -339,6 +339,26 @@ func Open(path string, mode int, perm uint32) (fd Handle, err error) {
var attrs uint32 = FILE_ATTRIBUTE_NORMAL
if perm&S_IWRITE == 0 {
attrs = FILE_ATTRIBUTE_READONLY
+ if createmode == CREATE_ALWAYS {
+ // We have been asked to create a read-only file.
+ // If the file already exists, the semantics of
+ // the Unix open system call is to preserve the
+ // existing permissions. If we pass CREATE_ALWAYS
+ // and FILE_ATTRIBUTE_READONLY to CreateFile,
+ // and the file already exists, CreateFile will
+ // change the file permissions.
+ // Avoid that to preserve the Unix semantics.
+ h, e := CreateFile(pathp, access, sharemode, sa, TRUNCATE_EXISTING, FILE_ATTRIBUTE_NORMAL, 0)
+ switch e {
+ case ERROR_FILE_NOT_FOUND, _ERROR_BAD_NETPATH, ERROR_PATH_NOT_FOUND:
+ // File does not exist. These are the same
+ // errors as Errno.Is checks for ErrNotExist.
+ // Carry on to create the file.
+ default:
+ // Success or some different error.
+ return h, e
+ }
+ }
}
h, e := CreateFile(pathp, access, sharemode, sa, createmode, attrs, 0)
return h, e
diff --git a/src/testing/benchmark.go b/src/testing/benchmark.go
index 88ba0f0242..52766005bf 100644
--- a/src/testing/benchmark.go
+++ b/src/testing/benchmark.go
@@ -526,6 +526,7 @@ func runBenchmarks(importPath string, matchString func(pat, str string) (bool, e
name: "Main",
w: os.Stdout,
chatty: *chatty,
+ bench: true,
},
importPath: importPath,
benchFunc: func(b *B) {
@@ -559,6 +560,7 @@ func (ctx *benchContext) processBench(b *B) {
name: b.name,
w: b.w,
chatty: b.chatty,
+ bench: true,
},
benchFunc: b.benchFunc,
benchTime: b.benchTime,
@@ -624,6 +626,7 @@ func (b *B) Run(name string, f func(b *B)) bool {
creator: pc[:n],
w: b.w,
chatty: b.chatty,
+ bench: true,
},
importPath: b.importPath,
benchFunc: f,
diff --git a/src/testing/sub_test.go b/src/testing/sub_test.go
index 95f8220f81..8eb0084b1c 100644
--- a/src/testing/sub_test.go
+++ b/src/testing/sub_test.go
@@ -438,8 +438,6 @@ func TestTRun(t *T) {
}, {
// A chatty test should always log with fmt.Print, even if the
// parent test has completed.
- // TODO(deklerk) Capture the log of fmt.Print and assert that the
- // subtest message is not lost.
desc: "log in finished sub test with chatty",
ok: false,
chatty: true,
@@ -477,35 +475,37 @@ func TestTRun(t *T) {
},
}}
for _, tc := range testCases {
- ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
- buf := &bytes.Buffer{}
- root := &T{
- common: common{
- signal: make(chan bool),
- name: "Test",
- w: buf,
- chatty: tc.chatty,
- },
- context: ctx,
- }
- ok := root.Run(tc.desc, tc.f)
- ctx.release()
+ t.Run(tc.desc, func(t *T) {
+ ctx := newTestContext(tc.maxPar, newMatcher(regexp.MatchString, "", ""))
+ buf := &bytes.Buffer{}
+ root := &T{
+ common: common{
+ signal: make(chan bool),
+ name: "Test",
+ w: buf,
+ chatty: tc.chatty,
+ },
+ context: ctx,
+ }
+ ok := root.Run(tc.desc, tc.f)
+ ctx.release()
- if ok != tc.ok {
- t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
- }
- if ok != !root.Failed() {
- t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
- }
- if ctx.running != 0 || ctx.numWaiting != 0 {
- t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
- }
- got := strings.TrimSpace(buf.String())
- want := strings.TrimSpace(tc.output)
- re := makeRegexp(want)
- if ok, err := regexp.MatchString(re, got); !ok || err != nil {
- t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
- }
+ if ok != tc.ok {
+ t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, tc.ok)
+ }
+ if ok != !root.Failed() {
+ t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+ }
+ if ctx.running != 0 || ctx.numWaiting != 0 {
+ t.Errorf("%s:running and waiting non-zero: got %d and %d", tc.desc, ctx.running, ctx.numWaiting)
+ }
+ got := strings.TrimSpace(buf.String())
+ want := strings.TrimSpace(tc.output)
+ re := makeRegexp(want)
+ if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+ t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+ }
+ })
}
}
@@ -655,43 +655,45 @@ func TestBRun(t *T) {
},
}}
for _, tc := range testCases {
- var ok bool
- buf := &bytes.Buffer{}
- // This is almost like the Benchmark function, except that we override
- // the benchtime and catch the failure result of the subbenchmark.
- root := &B{
- common: common{
- signal: make(chan bool),
- name: "root",
- w: buf,
- chatty: tc.chatty,
- },
- benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
- benchTime: benchTimeFlag{d: 1 * time.Microsecond},
- }
- root.runN(1)
- if ok != !tc.failed {
- t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
- }
- if !ok != root.Failed() {
- t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
- }
- // All tests are run as subtests
- if root.result.N != 1 {
- t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
- }
- got := strings.TrimSpace(buf.String())
- want := strings.TrimSpace(tc.output)
- re := makeRegexp(want)
- if ok, err := regexp.MatchString(re, got); !ok || err != nil {
- t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
- }
+ t.Run(tc.desc, func(t *T) {
+ var ok bool
+ buf := &bytes.Buffer{}
+ // This is almost like the Benchmark function, except that we override
+ // the benchtime and catch the failure result of the subbenchmark.
+ root := &B{
+ common: common{
+ signal: make(chan bool),
+ name: "root",
+ w: buf,
+ chatty: tc.chatty,
+ },
+ benchFunc: func(b *B) { ok = b.Run("test", tc.f) }, // Use Run to catch failure.
+ benchTime: benchTimeFlag{d: 1 * time.Microsecond},
+ }
+ root.runN(1)
+ if ok != !tc.failed {
+ t.Errorf("%s:ok: got %v; want %v", tc.desc, ok, !tc.failed)
+ }
+ if !ok != root.Failed() {
+ t.Errorf("%s:root failed: got %v; want %v", tc.desc, !ok, root.Failed())
+ }
+ // All tests are run as subtests
+ if root.result.N != 1 {
+ t.Errorf("%s: N for parent benchmark was %d; want 1", tc.desc, root.result.N)
+ }
+ got := strings.TrimSpace(buf.String())
+ want := strings.TrimSpace(tc.output)
+ re := makeRegexp(want)
+ if ok, err := regexp.MatchString(re, got); !ok || err != nil {
+ t.Errorf("%s:output:\ngot:\n%s\nwant:\n%s", tc.desc, got, want)
+ }
+ })
}
}
func makeRegexp(s string) string {
s = regexp.QuoteMeta(s)
- s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d:`)
+ s = strings.ReplaceAll(s, ":NNN:", `:\d\d\d\d?:`)
s = strings.ReplaceAll(s, "N\\.NNs", `\d*\.\d*s`)
return s
}
diff --git a/src/testing/testing.go b/src/testing/testing.go
index 90c15a2cff..85da6bb02a 100644
--- a/src/testing/testing.go
+++ b/src/testing/testing.go
@@ -219,9 +219,12 @@
// directly. TestMain runs in the main goroutine and can do whatever setup
// and teardown is necessary around a call to m.Run. m.Run will return an exit
// code that may be passed to os.Exit. If TestMain returns, the test wrapper
-// will pass the result of m.Run to os.Exit itself. When TestMain is called,
-// flag.Parse has not been run. If TestMain depends on command-line flags,
-// including those of the testing package, it should call flag.Parse explicitly.
+// will pass the result of m.Run to os.Exit itself.
+//
+// When TestMain is called, flag.Parse has not been run. If TestMain depends on
+// command-line flags, including those of the testing package, it should call
+// flag.Parse explicitly. Command line flags are always parsed by the time test
+// or benchmark functions run.
//
// A simple implementation of TestMain is:
//
@@ -322,6 +325,7 @@ var (
cpuListStr *string
parallel *int
testlog *string
+ printer *testPrinter
haveExamples bool // are there examples?
@@ -331,6 +335,48 @@ var (
numFailed uint32 // number of test failures
)
+type testPrinter struct {
+ chatty bool
+
+ lastNameMu sync.Mutex // guards lastName
+ lastName string // last printed test name in chatty mode
+}
+
+func newTestPrinter(chatty bool) *testPrinter {
+ return &testPrinter{
+ chatty: chatty,
+ }
+}
+
+func (p *testPrinter) Print(testName, out string) {
+ p.Fprint(os.Stdout, testName, out)
+}
+
+func (p *testPrinter) Fprint(w io.Writer, testName, out string) {
+ p.lastNameMu.Lock()
+ defer p.lastNameMu.Unlock()
+
+ if !p.chatty ||
+ strings.HasPrefix(out, "--- PASS") ||
+ strings.HasPrefix(out, "--- FAIL") ||
+ strings.HasPrefix(out, "=== CONT") ||
+ strings.HasPrefix(out, "=== RUN") {
+ p.lastName = testName
+ fmt.Fprint(w, out)
+ return
+ }
+
+ if p.lastName == "" {
+ p.lastName = testName
+ } else if p.lastName != testName {
+ // Always printed as-is, with 0 decoration or indentation. So, we skip
+ // printing to w.
+ fmt.Printf("=== CONT %s\n", testName)
+ p.lastName = testName
+ }
+ fmt.Fprint(w, out)
+}
+
// The maximum number of stack frames to go through when skipping helper functions for
// the purpose of decorating log messages.
const maxStackLen = 50
@@ -351,10 +397,11 @@ type common struct {
cleanupPc []uintptr // The stack trace at the point where Cleanup was called.
chatty bool // A copy of the chatty flag.
+ bench bool // Whether the current test is a benchmark.
finished bool // Test function has completed.
- hasSub int32 // written atomically
- raceErrors int // number of races detected during test
- runner string // function name of tRunner running the test
+ hasSub int32 // Written atomically.
+ raceErrors int // Number of races detected during test.
+ runner string // Function name of tRunner running the test.
parent *common
level int // Nesting depth of test or benchmark.
@@ -369,6 +416,7 @@ type common struct {
tempDirOnce sync.Once
tempDir string
tempDirErr error
+ tempDirSeq int32
}
// Short reports whether the -test.short flag is set.
@@ -492,9 +540,6 @@ func (c *common) decorate(s string, skip int) string {
buf := new(strings.Builder)
// Every line is indented at least 4 spaces.
buf.WriteString(" ")
- if c.chatty {
- fmt.Fprintf(buf, "%s: ", c.name)
- }
fmt.Fprintf(buf, "%s:%d: ", file, line)
lines := strings.Split(s, "\n")
if l := len(lines); l > 1 && lines[l-1] == "" {
@@ -513,12 +558,12 @@ func (c *common) decorate(s string, skip int) string {
// flushToParent writes c.output to the parent after first writing the header
// with the given format and arguments.
-func (c *common) flushToParent(format string, args ...interface{}) {
+func (c *common) flushToParent(testName, format string, args ...interface{}) {
p := c.parent
p.mu.Lock()
defer p.mu.Unlock()
- fmt.Fprintf(p.w, format, args...)
+ printer.Fprint(p.w, testName, fmt.Sprintf(format, args...))
c.mu.Lock()
defer c.mu.Unlock()
@@ -693,7 +738,14 @@ func (c *common) logDepth(s string, depth int) {
panic("Log in goroutine after " + c.name + " has completed")
} else {
if c.chatty {
- fmt.Print(c.decorate(s, depth+1))
+ if c.bench {
+ // Benchmarks don't print === CONT, so we should skip the test
+ // printer and just print straight to stdout.
+ fmt.Print(c.decorate(s, depth+1))
+ } else {
+ printer.Print(c.name, c.decorate(s, depth+1))
+ }
+
return
}
c.output = append(c.output, c.decorate(s, depth+1)...)
@@ -818,12 +870,13 @@ var tempDirReplacer struct {
}
// TempDir returns a temporary directory for the test to use.
-// It is lazily created on first access, and calls t.Fatal if the directory
-// creation fails.
-// Subsequent calls to t.TempDir return the same directory.
// The directory is automatically removed by Cleanup when the test and
// all its subtests complete.
+// Each subsequent call to t.TempDir returns a unique directory;
+// if the directory creation fails, TempDir terminates the test by calling Fatal.
func (c *common) TempDir() string {
+ // Use a single parent directory for all the temporary directories
+ // created by a test, each numbered sequentially.
c.tempDirOnce.Do(func() {
c.Helper()
@@ -846,7 +899,12 @@ func (c *common) TempDir() string {
if c.tempDirErr != nil {
c.Fatalf("TempDir: %v", c.tempDirErr)
}
- return c.tempDir
+ seq := atomic.AddInt32(&c.tempDirSeq, 1)
+ dir := fmt.Sprintf("%s%c%03d", c.tempDir, os.PathSeparator, seq)
+ if err := os.Mkdir(dir, 0777); err != nil {
+ c.Fatalf("TempDir: %v", err)
+ }
+ return dir
}
// panicHanding is an argument to runCleanup.
@@ -932,7 +990,7 @@ func (t *T) Parallel() {
for ; root.parent != nil; root = root.parent {
}
root.mu.Lock()
- fmt.Fprintf(root.w, "=== CONT %s\n", t.name)
+ printer.Fprint(root.w, t.name, fmt.Sprintf("=== CONT %s\n", t.name))
root.mu.Unlock()
}
@@ -991,7 +1049,7 @@ func tRunner(t *T, fn func(t *T)) {
root.duration += time.Since(root.start)
d := root.duration
root.mu.Unlock()
- root.flushToParent("--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
+ root.flushToParent(root.name, "--- FAIL: %s (%s)\n", root.name, fmtDuration(d))
if r := root.parent.runCleanup(recoverAndReturnPanic); r != nil {
fmt.Fprintf(root.parent.w, "cleanup panicked with %v", r)
}
@@ -1090,7 +1148,7 @@ func (t *T) Run(name string, f func(t *T)) bool {
for ; root.parent != nil; root = root.parent {
}
root.mu.Lock()
- fmt.Fprintf(root.w, "=== RUN %s\n", t.name)
+ printer.Fprint(root.w, t.name, fmt.Sprintf("=== RUN %s\n", t.name))
root.mu.Unlock()
}
// Instead of reducing the running count of this test before calling the
@@ -1256,6 +1314,8 @@ func (m *M) Run() (code int) {
flag.Parse()
}
+ printer = newTestPrinter(Verbose())
+
if *parallel < 1 {
fmt.Fprintln(os.Stderr, "testing: -parallel can only be given a positive integer")
flag.Usage()
@@ -1299,12 +1359,12 @@ func (t *T) report() {
dstr := fmtDuration(t.duration)
format := "--- %s: %s (%s)\n"
if t.Failed() {
- t.flushToParent(format, "FAIL", t.name, dstr)
+ t.flushToParent(t.name, format, "FAIL", t.name, dstr)
} else if t.chatty {
if t.Skipped() {
- t.flushToParent(format, "SKIP", t.name, dstr)
+ t.flushToParent(t.name, format, "SKIP", t.name, dstr)
} else {
- t.flushToParent(format, "PASS", t.name, dstr)
+ t.flushToParent(t.name, format, "PASS", t.name, dstr)
}
}
}
diff --git a/src/testing/testing_test.go b/src/testing/testing_test.go
index 1340dae5c4..dbef7066e0 100644
--- a/src/testing/testing_test.go
+++ b/src/testing/testing_test.go
@@ -7,6 +7,7 @@ package testing_test
import (
"io/ioutil"
"os"
+ "path/filepath"
"testing"
)
@@ -55,8 +56,11 @@ func testTempDir(t *testing.T) {
t.Fatal("expected dir")
}
dir2 := t.TempDir()
- if dir != dir2 {
- t.Fatal("directory changed between calls")
+ if dir == dir2 {
+ t.Fatal("subsequent calls to TempDir returned the same directory")
+ }
+ if filepath.Dir(dir) != filepath.Dir(dir2) {
+ t.Fatalf("calls to TempDir do not share a parent; got %q, %q", dir, dir2)
}
dirCh <- dir
fi, err := os.Stat(dir)
diff --git a/src/text/template/link_test.go b/src/text/template/link_test.go
index b7415d29bb..4eac7e6755 100644
--- a/src/text/template/link_test.go
+++ b/src/text/template/link_test.go
@@ -49,7 +49,7 @@ func main() {
if err := ioutil.WriteFile(filepath.Join(td, "x.go"), []byte(prog), 0644); err != nil {
t.Fatal(err)
}
- cmd := exec.Command("go", "build", "-o", "x.exe", "x.go")
+ cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "x.exe", "x.go")
cmd.Dir = td
if out, err := cmd.CombinedOutput(); err != nil {
t.Fatalf("go build: %v, %s", err, out)
diff --git a/src/text/template/parse/node.go b/src/text/template/parse/node.go
index 1c116ea6fa..dddc7752a2 100644
--- a/src/text/template/parse/node.go
+++ b/src/text/template/parse/node.go
@@ -349,7 +349,7 @@ func (i *IdentifierNode) Copy() Node {
return NewIdentifier(i.Ident).SetTree(i.tr).SetPos(i.Pos)
}
-// AssignNode holds a list of variable names, possibly with chained field
+// VariableNode holds a list of variable names, possibly with chained field
// accesses. The dollar sign is part of the (first) name.
type VariableNode struct {
NodeType
diff --git a/src/time/example_test.go b/src/time/example_test.go
index 15811a62d3..0afb18aba6 100644
--- a/src/time/example_test.go
+++ b/src/time/example_test.go
@@ -50,10 +50,11 @@ func ExampleDuration_Round() {
}
func ExampleDuration_String() {
- t1 := time.Date(2016, time.August, 15, 0, 0, 0, 0, time.UTC)
- t2 := time.Date(2017, time.February, 16, 0, 0, 0, 0, time.UTC)
- fmt.Println(t2.Sub(t1).String())
- // Output: 4440h0m0s
+ fmt.Println(1*time.Hour + 2*time.Minute + 300*time.Millisecond)
+ fmt.Println(300 * time.Millisecond)
+ // Output:
+ // 1h2m0.3s
+ // 300ms
}
func ExampleDuration_Truncate() {
diff --git a/src/time/format.go b/src/time/format.go
index b74108f0e7..f11fb7ed30 100644
--- a/src/time/format.go
+++ b/src/time/format.go
@@ -67,7 +67,7 @@ import "errors"
// that insist on that format, and RFC3339 should be preferred for new protocols.
// RFC3339, RFC822, RFC822Z, RFC1123, and RFC1123Z are useful for formatting;
// when used with time.Parse they do not accept all the time formats
-// permitted by the RFCs.
+// permitted by the RFCs and they do accept time formats not formally defined.
// The RFC3339Nano format removes trailing zeros from the seconds field
// and thus may not sort correctly once formatted.
const (
diff --git a/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go b/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go
index b26376aeca..d3596ee66f 100644
--- a/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go
+++ b/src/vendor/golang.org/x/crypto/cryptobyte/asn1.go
@@ -230,12 +230,12 @@ func (b *Builder) AddASN1(tag asn1.Tag, f BuilderContinuation) {
// String
-// ReadASN1Boolean decodes an ASN.1 INTEGER and converts it to a boolean
+// ReadASN1Boolean decodes an ASN.1 BOOLEAN and converts it to a boolean
// representation into out and advances. It reports whether the read
// was successful.
func (s *String) ReadASN1Boolean(out *bool) bool {
var bytes String
- if !s.ReadASN1(&bytes, asn1.INTEGER) || len(bytes) != 1 {
+ if !s.ReadASN1(&bytes, asn1.BOOLEAN) || len(bytes) != 1 {
return false
}
diff --git a/src/vendor/golang.org/x/net/dns/dnsmessage/message.go b/src/vendor/golang.org/x/net/dns/dnsmessage/message.go
index da8bafd921..654f191f8a 100644
--- a/src/vendor/golang.org/x/net/dns/dnsmessage/message.go
+++ b/src/vendor/golang.org/x/net/dns/dnsmessage/message.go
@@ -14,7 +14,6 @@ package dnsmessage
import (
"errors"
- "fmt"
)
// Message formats
@@ -2141,7 +2140,7 @@ func unpackResourceBody(msg []byte, off int, hdr ResourceHeader) (ResourceBody,
return nil, off, &nestedError{name + " record", err}
}
if r == nil {
- return nil, off, fmt.Errorf("invalid resource type: %d", hdr.Type)
+ return nil, off, errors.New("invalid resource type: " + hdr.Type.String())
}
return r, off + int(hdr.Length), nil
}
diff --git a/src/vendor/modules.txt b/src/vendor/modules.txt
index 7c42df8348..e687d77b4d 100644
--- a/src/vendor/modules.txt
+++ b/src/vendor/modules.txt
@@ -1,4 +1,4 @@
-# golang.org/x/crypto v0.0.0-20200429183012-4b2356b1ed79
+# golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9
## explicit
golang.org/x/crypto/chacha20
golang.org/x/crypto/chacha20poly1305
@@ -8,7 +8,7 @@ golang.org/x/crypto/curve25519
golang.org/x/crypto/hkdf
golang.org/x/crypto/internal/subtle
golang.org/x/crypto/poly1305
-# golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5
+# golang.org/x/net v0.0.0-20200707034311-ab3426394381
## explicit
golang.org/x/net/dns/dnsmessage
golang.org/x/net/http/httpguts
diff --git a/test/codegen/arithmetic.go b/test/codegen/arithmetic.go
index a076664e8e..8f25974376 100644
--- a/test/codegen/arithmetic.go
+++ b/test/codegen/arithmetic.go
@@ -451,3 +451,14 @@ func addSpecial(a, b, c uint32) (uint32, uint32, uint32) {
c += 128
return a, b, c
}
+
+
+// Divide -> shift rules usually require fixup for negative inputs.
+// If the input is non-negative, make sure the fixup is eliminated.
+func divInt(v int64) int64 {
+ if v < 0 {
+ return 0
+ }
+ // amd64:-`.*SARQ.*63,`, -".*SHRQ", ".*SARQ.*[$]9,"
+ return v / 512
+}
diff --git a/test/codegen/comparisons.go b/test/codegen/comparisons.go
index c020ea8eb7..90808573c2 100644
--- a/test/codegen/comparisons.go
+++ b/test/codegen/comparisons.go
@@ -248,3 +248,162 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
}
return 0
}
+
+// The following CmpToZero_ex* check that cmp|cmn with bmi|bpl are generated for
+// 'comparing to zero' expressions
+
+// var + const
+// 'x-const' might be canonicalized to 'x+(-const)', so we check both
+// CMN and CMP for subtraction expressions to make the pattern robust.
+func CmpToZero_ex1(a int64, e int32) int {
+ // arm64:`CMN`,-`ADD`,`(BMI|BPL)`
+ if a+3 < 0 {
+ return 1
+ }
+
+ // arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
+ if a+5 <= 0 {
+ return 1
+ }
+
+ // arm64:`CMN`,-`ADD`,`(BMI|BPL)`
+ if a+13 >= 0 {
+ return 2
+ }
+
+ // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
+ if a-7 < 0 {
+ return 3
+ }
+
+ // arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
+ if a-11 >= 0 {
+ return 4
+ }
+
+ // arm64:`CMP|CMN`,-`(ADD|SUB)`,`BEQ`,`(BMI|BPL)`
+ if a-19 > 0 {
+ return 4
+ }
+
+ // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
+ // arm:`CMN`,-`ADD`,`(BMI|BPL)`
+ if e+3 < 0 {
+ return 5
+ }
+
+ // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
+ // arm:`CMN`,-`ADD`,`(BMI|BPL)`
+ if e+13 >= 0 {
+ return 6
+ }
+
+ // arm64:`CMPW|CMNW`,`(BMI|BPL)`
+ // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
+ if e-7 < 0 {
+ return 7
+ }
+
+ // arm64:`CMPW|CMNW`,`(BMI|BPL)`
+ // arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
+ if e-11 >= 0 {
+ return 8
+ }
+
+ return 0
+}
+
+// var + var
+// TODO: optimize 'var - var'
+func CmpToZero_ex2(a, b, c int64, e, f, g int32) int {
+ // arm64:`CMN`,-`ADD`,`(BMI|BPL)`
+ if a+b < 0 {
+ return 1
+ }
+
+ // arm64:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
+ if a+c <= 0 {
+ return 1
+ }
+
+ // arm64:`CMN`,-`ADD`,`(BMI|BPL)`
+ if b+c >= 0 {
+ return 2
+ }
+
+ // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
+ // arm:`CMN`,-`ADD`,`(BMI|BPL)`
+ if e+f < 0 {
+ return 5
+ }
+
+ // arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
+ // arm:`CMN`,-`ADD`,`(BMI|BPL)`
+ if f+g >= 0 {
+ return 6
+ }
+ return 0
+}
+
+// var + var*var
+func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int {
+ // arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)`
+ if a+b*c < 0 {
+ return 1
+ }
+
+ // arm64:`CMN`,-`MADD`,`MUL`,`(BMI|BPL)`
+ if b+c*d >= 0 {
+ return 2
+ }
+
+ // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
+ // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
+ if e+f*g > 0 {
+ return 5
+ }
+
+ // arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
+ // arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
+ if f+g*h <= 0 {
+ return 6
+ }
+ return 0
+}
+
+// var - var*var
+func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int {
+ // arm64:`CMP`,-`MSUB`,`MUL`,`BEQ`,`(BMI|BPL)`
+ if a-b*c > 0 {
+ return 1
+ }
+
+ // arm64:`CMP`,-`MSUB`,`MUL`,`(BMI|BPL)`
+ if b-c*d >= 0 {
+ return 2
+ }
+
+ // arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)`
+ if e-f*g < 0 {
+ return 5
+ }
+
+ // arm64:`CMPW`,-`MSUBW`,`MULW`,`(BMI|BPL)`
+ if f-g*h >= 0 {
+ return 6
+ }
+ return 0
+}
+
+func CmpToZero_ex5(e, f int32, u uint32) int {
+ // arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
+ if e+f<<1 > 0 {
+ return 1
+ }
+
+ // arm:`CMP`,-`SUB`,`(BMI|BPL)`
+ if f-int32(u>>2) >= 0 {
+ return 2
+ }
+ return 0
+}
diff --git a/test/codegen/slices.go b/test/codegen/slices.go
index cf569e27fb..40e857f9f6 100644
--- a/test/codegen/slices.go
+++ b/test/codegen/slices.go
@@ -104,6 +104,189 @@ func SliceExtensionInt64(s []int, l64 int64) []int {
return append(s, make([]int, l64)...)
}
+// ------------------ //
+// Make+Copy //
+// ------------------ //
+
+// Issue #26252 - avoid memclr for make+copy
+
+func SliceMakeCopyLen(s []int) []int {
+ // amd64:`.*runtime\.mallocgc`
+ // amd64:`.*runtime\.memmove`
+ // amd64:-`.*runtime\.makeslice`
+ a := make([]int, len(s))
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyLenPtr(s []*int) []*int {
+ // amd64:`.*runtime\.makeslicecopy`
+ // amd64:-`.*runtime\.makeslice\(`
+ // amd64:-`.*runtime\.typedslicecopy
+ a := make([]*int, len(s))
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyConst(s []int) []int {
+ // amd64:`.*runtime\.makeslicecopy`
+ // amd64:-`.*runtime\.makeslice\(`
+ // amd64:-`.*runtime\.memmove`
+ a := make([]int, 4)
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyConstPtr(s []*int) []*int {
+ // amd64:`.*runtime\.makeslicecopy`
+ // amd64:-`.*runtime\.makeslice\(`
+ // amd64:-`.*runtime\.typedslicecopy
+ a := make([]*int, 4)
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoOptNoDeref(s []*int) []*int {
+ a := new([]*int)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ *a = make([]*int, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(*a, s)
+ return *a
+}
+
+func SliceMakeCopyNoOptNoVar(s []*int) []*int {
+ a := make([][]*int, 1)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a[0] = make([]*int, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(a[0], s)
+ return a[0]
+}
+
+func SliceMakeCopyNoOptBlank(s []*int) []*int {
+ var a []*int
+ // amd64:-`.*runtime\.makeslicecopy`
+ _ = make([]*int, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoOptNoMake(s []*int) []*int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:-`.*runtime\.objectnew`
+ a := *new([]*int)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoOptNoHeapAlloc(s []*int) int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ a := make([]*int, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(a, s)
+ return cap(a)
+}
+
+func SliceMakeCopyNoOptNoCap(s []*int) []*int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 0, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.typedslicecopy`
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoOptNoCopy(s []*int) []*int {
+ copy := func(x, y []*int) {}
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 4)
+ // amd64:-`.*runtime\.makeslicecopy`
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoOptWrongOrder(s []*int) []*int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 4)
+ // amd64:`.*runtime\.typedslicecopy`
+ // amd64:-`.*runtime\.makeslicecopy`
+ copy(s, a)
+ return a
+}
+
+func SliceMakeCopyNoOptWrongAssign(s []*int) []*int {
+ var a []*int
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ s = make([]*int, 4)
+ // amd64:`.*runtime\.typedslicecopy`
+ // amd64:-`.*runtime\.makeslicecopy`
+ copy(a, s)
+ return s
+}
+
+func SliceMakeCopyNoOptCopyLength(s []*int) (int, []*int) {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 4)
+ // amd64:`.*runtime\.typedslicecopy`
+ // amd64:-`.*runtime\.makeslicecopy`
+ n := copy(a, s)
+ return n, a
+}
+
+func SliceMakeCopyNoOptSelfCopy(s []*int) []*int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 4)
+ // amd64:`.*runtime\.typedslicecopy`
+ // amd64:-`.*runtime\.makeslicecopy`
+ copy(a, a)
+ return a
+}
+
+func SliceMakeCopyNoOptTargetReference(s []*int) []*int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]*int, 4)
+ // amd64:`.*runtime\.typedslicecopy`
+ // amd64:-`.*runtime\.makeslicecopy`
+ copy(a, s[:len(a)])
+ return a
+}
+
+func SliceMakeCopyNoOptCap(s []int) []int {
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.makeslice\(`
+ a := make([]int, len(s), 9)
+ // amd64:-`.*runtime\.makeslicecopy`
+ // amd64:`.*runtime\.memmove`
+ copy(a, s)
+ return a
+}
+
+func SliceMakeCopyNoMemmoveDifferentLen(s []int) []int {
+ // amd64:`.*runtime\.makeslicecopy`
+ // amd64:-`.*runtime\.memmove`
+ a := make([]int, len(s)-1)
+ // amd64:-`.*runtime\.memmove`
+ copy(a, s)
+ return a
+}
+
// ---------------------- //
// Nil check of &s[0] //
// ---------------------- //
diff --git a/test/fixedbugs/issue25727.go b/test/fixedbugs/issue25727.go
index 9b7c804a0e..da7c94cc12 100644
--- a/test/fixedbugs/issue25727.go
+++ b/test/fixedbugs/issue25727.go
@@ -9,13 +9,13 @@ 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 _ = 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$"
+var _ = http.Server{DoneChan: nil} // ERROR "unknown field 'DoneChan' in struct literal of type http.Server$"
type foo struct {
- bar int
+ bar int
}
var _ = &foo{bAr: 10} // ERROR "unknown field 'bAr' in struct literal.+ .but does have bar.$"
diff --git a/test/fixedbugs/issue31053.dir/f1.go b/test/fixedbugs/issue31053.dir/f1.go
new file mode 100644
index 0000000000..610f393818
--- /dev/null
+++ b/test/fixedbugs/issue31053.dir/f1.go
@@ -0,0 +1,18 @@
+// Copyright 2019 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 f1
+
+type Foo struct {
+ doneChan chan bool
+ Name string
+ fOO int
+ hook func()
+}
+
+func (f *Foo) Exported() {
+}
+
+func (f *Foo) unexported() {
+}
diff --git a/test/fixedbugs/issue31053.dir/main.go b/test/fixedbugs/issue31053.dir/main.go
new file mode 100644
index 0000000000..895c262164
--- /dev/null
+++ b/test/fixedbugs/issue31053.dir/main.go
@@ -0,0 +1,42 @@
+// errorcheck
+
+// Copyright 2019 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
+
+import "./f1"
+
+func main() {
+ f := f1.Foo{
+ doneChan: nil, // ERROR "cannot refer to unexported field 'doneChan' in struct literal of type f1.Foo"
+ DoneChan: nil, // ERROR "unknown field 'DoneChan' in struct literal of type f1.Foo"
+ Name: "hey",
+ name: "there", // ERROR "unknown field 'name' in struct literal of type f1.Foo .but does have Name."
+ noSuchPrivate: true, // ERROR "unknown field 'noSuchPrivate' in struct literal of type f1.Foo"
+ NoSuchPublic: true, // ERROR "unknown field 'NoSuchPublic' in struct literal of type f1.Foo"
+ foo: true, // ERROR "unknown field 'foo' in struct literal of type f1.Foo"
+ hook: func() {}, // ERROR "cannot refer to unexported field 'hook' in struct literal of type f1.Foo"
+ unexported: func() {}, // ERROR "unknown field 'unexported' in struct literal of type f1.Foo"
+ Exported: func() {}, // ERROR "unknown field 'Exported' in struct literal of type f1.Foo"
+ }
+ f.doneChan = nil // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan."
+ f.DoneChan = nil // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan."
+ f.name = nil // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name."
+
+ _ = f.doneChan // ERROR "f.doneChan undefined .cannot refer to unexported field or method doneChan."
+ _ = f.DoneChan // ERROR "f.DoneChan undefined .type f1.Foo has no field or method DoneChan."
+ _ = f.Name
+ _ = f.name // ERROR "f.name undefined .type f1.Foo has no field or method name, but does have Name."
+ _ = f.noSuchPrivate // ERROR "f.noSuchPrivate undefined .type f1.Foo has no field or method noSuchPrivate."
+ _ = f.NoSuchPublic // ERROR "f.NoSuchPublic undefined .type f1.Foo has no field or method NoSuchPublic."
+ _ = f.foo // ERROR "f.foo undefined .type f1.Foo has no field or method foo."
+ _ = f.Exported
+ _ = f.exported // ERROR "f.exported undefined .type f1.Foo has no field or method exported, but does have Exported."
+ _ = f.Unexported // ERROR "f.Unexported undefined .type f1.Foo has no field or method Unexported."
+ _ = f.unexported // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ f.unexported = 10 // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ f.unexported() // ERROR "f.unexported undefined .cannot refer to unexported field or method f1..\*Foo..unexported."
+ _ = f.hook // ERROR "f.hook undefined .cannot refer to unexported field or method hook."
+}
diff --git a/test/fixedbugs/issue31053.go b/test/fixedbugs/issue31053.go
new file mode 100644
index 0000000000..a33d3ff347
--- /dev/null
+++ b/test/fixedbugs/issue31053.go
@@ -0,0 +1,7 @@
+// errorcheckdir
+
+// Copyright 2019 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/issue36437.go b/test/fixedbugs/issue36437.go
new file mode 100644
index 0000000000..f96544beff
--- /dev/null
+++ b/test/fixedbugs/issue36437.go
@@ -0,0 +1,49 @@
+// run
+
+// +build !nacl,!js
+
+// Copyright 2020 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.
+
+// Tests that when non-existent files are passed to the
+// compiler, such as in:
+// go tool compile foo
+// we don't print the beginning position:
+// foo:0: open foo: no such file or directory
+// but instead omit it and print out:
+// open foo: no such file or directory
+
+package main
+
+import (
+ "fmt"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+)
+
+func main() {
+ tmpDir, err := ioutil.TempDir("", "issue36437")
+ if err != nil {
+ panic(err)
+ }
+ defer os.RemoveAll(tmpDir)
+
+ msgOrErr := func(msg []byte, err error) string {
+ if len(msg) == 0 && err != nil {
+ return err.Error()
+ }
+ return string(msg)
+ }
+
+ filename := "non-existent.go"
+ output, err := exec.Command("go", "tool", "compile", filename).CombinedOutput()
+ got := msgOrErr(output, err)
+
+ regFilenamePos := regexp.MustCompile(filename + ":\\d+")
+ if regFilenamePos.MatchString(got) {
+ fmt.Printf("Error message must not contain filename:pos, but got:\n%q\n", got)
+ }
+}
diff --git a/test/fixedbugs/issue37246.go b/test/fixedbugs/issue37246.go
new file mode 100644
index 0000000000..fe476daa39
--- /dev/null
+++ b/test/fixedbugs/issue37246.go
@@ -0,0 +1,23 @@
+// compile
+
+// Copyright 2020 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 n, a, b int64
+ for i := int64(2); i < 10; i++ {
+ for j := i; j < 10; j++ {
+ if ((n % (i * j)) == 0) && (j > 1 && (n/(i*j)) == 1) {
+ a, b = i, 0
+ a = n / (i * j)
+ }
+ }
+ }
+
+ if a != b && a != n {
+ println("yes")
+ }
+}
diff --git a/test/fixedbugs/issue38093.go b/test/fixedbugs/issue38093.go
new file mode 100644
index 0000000000..db92664a49
--- /dev/null
+++ b/test/fixedbugs/issue38093.go
@@ -0,0 +1,49 @@
+// +build js
+// run
+
+// Copyright 2020 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 race condition between timers and wasm calls that led to memory corruption.
+
+package main
+
+import (
+ "os"
+ "syscall/js"
+ "time"
+)
+
+func main() {
+ ch1 := make(chan struct{})
+
+ go func() {
+ for {
+ time.Sleep(5 * time.Millisecond)
+ ch1 <- struct{}{}
+ }
+ }()
+ go func() {
+ for {
+ time.Sleep(8 * time.Millisecond)
+ ch1 <- struct{}{}
+ }
+ }()
+ go func() {
+ time.Sleep(2 * time.Second)
+ os.Exit(0)
+ }()
+
+ for range ch1 {
+ ch2 := make(chan struct{}, 1)
+ f := js.FuncOf(func(this js.Value, args []js.Value) interface{} {
+ ch2 <- struct{}{}
+ return nil
+ })
+ defer f.Release()
+ fn := js.Global().Get("Function").New("cb", "cb();")
+ fn.Invoke(f)
+ <-ch2
+ }
+}
diff --git a/test/fixedbugs/issue38916.go b/test/fixedbugs/issue38916.go
new file mode 100644
index 0000000000..fb2ee3459d
--- /dev/null
+++ b/test/fixedbugs/issue38916.go
@@ -0,0 +1,14 @@
+// compile
+
+// Copyright 2020 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
+
+func f(b bool, c complex128) func(complex128) complex128 {
+ return func(p complex128) complex128 {
+ b = (p+1i == 0) && b
+ return (p + 2i) * (p + 3i - c)
+ }
+}
diff --git a/test/fixedbugs/issue39459.go b/test/fixedbugs/issue39459.go
new file mode 100644
index 0000000000..de78a17ce2
--- /dev/null
+++ b/test/fixedbugs/issue39459.go
@@ -0,0 +1,22 @@
+// compile
+
+// Copyright 2020 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 T struct { // big enough to be an unSSAable type
+ a, b, c, d, e, f int
+}
+
+func f(x interface{}, p *int) {
+ _ = *p // trigger nil check here, removing it from below
+ switch x := x.(type) {
+ case *T:
+ // Zero twice, so one of them will be removed by the deadstore pass
+ *x = T{}
+ *p = 0 // store op to prevent Zero ops from being optimized by the earlier opt pass rewrite rules
+ *x = T{}
+ }
+}
diff --git a/test/fixedbugs/issue39472.go b/test/fixedbugs/issue39472.go
new file mode 100644
index 0000000000..61444a28b9
--- /dev/null
+++ b/test/fixedbugs/issue39472.go
@@ -0,0 +1,12 @@
+// compile -N
+
+// Copyright 2020 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
+
+func f(x float64) bool {
+ x += 1
+ return (x != 0) == (x != 0)
+}
diff --git a/test/fixedbugs/issue39541.go b/test/fixedbugs/issue39541.go
new file mode 100644
index 0000000000..fba52916eb
--- /dev/null
+++ b/test/fixedbugs/issue39541.go
@@ -0,0 +1,33 @@
+// run
+
+// Copyright 2020 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 "reflect"
+
+func sub(args []reflect.Value) []reflect.Value {
+ type A struct {
+ s int
+ t int
+ }
+ return []reflect.Value{reflect.ValueOf(A{1, 2})}
+}
+
+func main() {
+ f := reflect.MakeFunc(reflect.TypeOf((func() interface{})(nil)), sub).Interface().(func() interface{})
+ c := make(chan bool, 100)
+ for i := 0; i < 100; i++ {
+ go func() {
+ for j := 0; j < 10000; j++ {
+ f()
+ }
+ c <- true
+ }()
+ }
+ for i := 0; i < 100; i++ {
+ <-c
+ }
+}
diff --git a/test/fixedbugs/issue39651.go b/test/fixedbugs/issue39651.go
new file mode 100644
index 0000000000..256a34dcb3
--- /dev/null
+++ b/test/fixedbugs/issue39651.go
@@ -0,0 +1,26 @@
+// run
+
+// Copyright 2020 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 float -> integer conversion doesn't clobber
+// flags.
+
+package main
+
+//go:noinline
+func f(x, y float64, a, b *bool, r *int64) {
+ *a = x < y // set flags
+ *r = int64(x) // clobber flags
+ *b = x == y // use flags
+}
+
+func main() {
+ var a, b bool
+ var r int64
+ f(1, 1, &a, &b, &r)
+ if a || !b {
+ panic("comparison incorrect")
+ }
+}
diff --git a/test/fixedbugs/issue8606.go b/test/fixedbugs/issue8606.go
new file mode 100644
index 0000000000..8c85069695
--- /dev/null
+++ b/test/fixedbugs/issue8606.go
@@ -0,0 +1,93 @@
+// run
+
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Check to make sure that we compare fields in order. See issue 8606.
+
+package main
+
+import "fmt"
+
+func main() {
+ type A [2]interface{}
+ type A2 [6]interface{}
+ type S struct{ x, y interface{} }
+ type S2 struct{ x, y, z, a, b, c interface{} }
+ type T1 struct {
+ i interface{}
+ a int64
+ j interface{}
+ }
+ type T2 struct {
+ i interface{}
+ a, b, c int64
+ j interface{}
+ }
+ type T3 struct {
+ i interface{}
+ s string
+ j interface{}
+ }
+ b := []byte{1}
+
+ for _, test := range []struct {
+ panic bool
+ a, b interface{}
+ }{
+ {false, A{1, b}, A{2, b}},
+ {true, A{b, 1}, A{b, 2}},
+ {false, A{1, b}, A{"2", b}},
+ {true, A{b, 1}, A{b, "2"}},
+
+ {false, A2{1, b}, A2{2, b}},
+ {true, A2{b, 1}, A2{b, 2}},
+ {false, A2{1, b}, A2{"2", b}},
+ {true, A2{b, 1}, A2{b, "2"}},
+
+ {false, S{1, b}, S{2, b}},
+ {true, S{b, 1}, S{b, 2}},
+ {false, S{1, b}, S{"2", b}},
+ {true, S{b, 1}, S{b, "2"}},
+
+ {false, S2{x: 1, y: b}, S2{x: 2, y: b}},
+ {true, S2{x: b, y: 1}, S2{x: b, y: 2}},
+ {false, S2{x: 1, y: b}, S2{x: "2", y: b}},
+ {true, S2{x: b, y: 1}, S2{x: b, y: "2"}},
+
+ {true, T1{i: b, a: 1}, T1{i: b, a: 2}},
+ {false, T1{a: 1, j: b}, T1{a: 2, j: b}},
+ {true, T2{i: b, a: 1}, T2{i: b, a: 2}},
+ {false, T2{a: 1, j: b}, T2{a: 2, j: b}},
+ {true, T3{i: b, s: "foo"}, T3{i: b, s: "bar"}},
+ {false, T3{s: "foo", j: b}, T3{s: "bar", j: b}},
+ {true, T3{i: b, s: "fooz"}, T3{i: b, s: "bar"}},
+ {false, T3{s: "fooz", j: b}, T3{s: "bar", j: b}},
+ } {
+ f := func() {
+ defer func() {
+ if recover() != nil {
+ panic(fmt.Sprintf("comparing %#v and %#v panicked", test.a, test.b))
+ }
+ }()
+ if test.a == test.b {
+ panic(fmt.Sprintf("values %#v and %#v should not be equal", test.a, test.b))
+ }
+ }
+ if test.panic {
+ shouldPanic(fmt.Sprintf("comparing %#v and %#v did not panic", test.a, test.b), f)
+ } else {
+ f() // should not panic
+ }
+ }
+}
+
+func shouldPanic(name string, f func()) {
+ defer func() {
+ if recover() == nil {
+ panic(name)
+ }
+ }()
+ f()
+}
diff --git a/test/makeslice.go b/test/makeslice.go
new file mode 100644
index 0000000000..0ffecd7c43
--- /dev/null
+++ b/test/makeslice.go
@@ -0,0 +1,149 @@
+// run
+
+// Copyright 2013 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 (
+ "strings"
+ "unsafe"
+)
+
+func main() {
+ n := -1
+ testInts(uint64(n))
+ testBytes(uint64(n))
+
+ var t *byte
+ if unsafe.Sizeof(t) == 8 {
+ // Test mem > maxAlloc
+ testInts(1 << 59)
+
+ // Test elem.size*cap overflow
+ testInts(1<<63 - 1)
+
+ testInts(1<<64 - 1)
+ testBytes(1<<64 - 1)
+ } else {
+ testInts(1<<31 - 1)
+
+ // Test elem.size*cap overflow
+ testInts(1<<32 - 1)
+ testBytes(1<<32 - 1)
+ }
+}
+
+func shouldPanic(str string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ panic("did not panic")
+ }
+ s := err.(error).Error()
+ if !strings.Contains(s, str) {
+ panic("got panic " + s + ", want " + str)
+ }
+ }()
+
+ f()
+}
+
+func testInts(n uint64) {
+ testMakeInts(n)
+ testMakeCopyInts(n)
+ testMakeInAppendInts(n)
+}
+
+func testBytes(n uint64) {
+ testMakeBytes(n)
+ testMakeCopyBytes(n)
+ testMakeInAppendBytes(n)
+}
+
+// Test make panics for given length or capacity n.
+func testMakeInts(n uint64) {
+ type T []int
+ shouldPanic("len out of range", func() { _ = make(T, int(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
+}
+
+func testMakeBytes(n uint64) {
+ type T []byte
+ shouldPanic("len out of range", func() { _ = make(T, int(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, uint(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, uint(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, int64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, int64(n)) })
+ shouldPanic("len out of range", func() { _ = make(T, uint64(n)) })
+ shouldPanic("cap out of range", func() { _ = make(T, 0, uint64(n)) })
+}
+
+// Test make+copy panics since the gc compiler optimizes these
+// to runtime.makeslicecopy calls.
+func testMakeCopyInts(n uint64) {
+ type T []int
+ var c = make(T, 8)
+ shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
+}
+
+func testMakeCopyBytes(n uint64) {
+ type T []byte
+ var c = make(T, 8)
+ shouldPanic("len out of range", func() { x := make(T, int(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, int(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, uint(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, uint(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, int64(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, int64(n)); copy(x, c) })
+ shouldPanic("len out of range", func() { x := make(T, uint64(n)); copy(x, c) })
+ shouldPanic("cap out of range", func() { x := make(T, 0, uint64(n)); copy(x, c) })
+}
+
+// Test make in append panics for int slices since the gc compiler optimizes makes in appends.
+func testMakeInAppendInts(n uint64) {
+ type T []int
+ for _, length := range []int{0, 1} {
+ t := make(T, length)
+ shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
+ }
+}
+
+func testMakeInAppendBytes(n uint64) {
+ type T []byte
+ for _, length := range []int{0, 1} {
+ t := make(T, length)
+ shouldPanic("len out of range", func() { _ = append(t, make(T, int(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, uint(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, int64(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, int64(n))...) })
+ shouldPanic("len out of range", func() { _ = append(t, make(T, uint64(n))...) })
+ shouldPanic("cap out of range", func() { _ = append(t, make(T, 0, uint64(n))...) })
+ }
+}
diff --git a/test/prove.go b/test/prove.go
index e5636a452e..d37021d283 100644
--- a/test/prove.go
+++ b/test/prove.go
@@ -956,6 +956,70 @@ func negIndex2(n int) {
useSlice(c)
}
+// Check that prove is zeroing these right shifts of positive ints by bit-width - 1.
+// e.g (Rsh64x64 <t> n (Const64 <typ.UInt64> [63])) && ft.isNonNegative(n) -> 0
+func sh64(n int64) int64 {
+ if n < 0 {
+ return n
+ }
+ return n >> 63 // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func sh32(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n >> 31 // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
+func sh32x64(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n >> uint64(31) // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
+func sh16(n int16) int16 {
+ if n < 0 {
+ return n
+ }
+ return n >> 15 // ERROR "Proved Rsh16x64 shifts to zero"
+}
+
+func sh64noopt(n int64) int64 {
+ return n >> 63 // not optimized; n could be negative
+}
+
+// These cases are division of a positive signed integer by a power of 2.
+// The opt pass doesnt have sufficient information to see that n is positive.
+// So, instead, opt rewrites the division with a less-than-optimal replacement.
+// Prove, which can see that n is nonnegative, cannot see the division because
+// opt, an earlier pass, has already replaced it.
+// The fix for this issue allows prove to zero a right shift that was added as
+// part of the less-than-optimal reqwrite. That change by prove then allows
+// lateopt to clean up all the unneccesary parts of the original division
+// replacement. See issue #36159.
+func divShiftClean(n int) int {
+ if n < 0 {
+ return n
+ }
+ return n / int(8) // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func divShiftClean64(n int64) int64 {
+ if n < 0 {
+ return n
+ }
+ return n / int64(16) // ERROR "Proved Rsh64x64 shifts to zero"
+}
+
+func divShiftClean32(n int32) int32 {
+ if n < 0 {
+ return n
+ }
+ return n / int32(16) // ERROR "Proved Rsh32x64 shifts to zero"
+}
+
//go:noinline
func useInt(a int) {
}
diff --git a/test/winbatch.go b/test/winbatch.go
index 30e0e3c982..c3b48d385c 100644
--- a/test/winbatch.go
+++ b/test/winbatch.go
@@ -4,8 +4,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Check that batch files are maintained as CRLF files (consistent behaviour
-// on all operating systems). See https://github.com/golang/go/issues/37791
+// Check that batch files are maintained as CRLF files (consistent
+// behavior on all operating systems). See golang.org/issue/37791.
package main
@@ -13,18 +13,56 @@ import (
"bytes"
"fmt"
"io/ioutil"
+ "log"
"os"
"path/filepath"
"runtime"
+ "strings"
)
func main() {
- batches, _ := filepath.Glob(runtime.GOROOT() + "/src/*.bat")
- for _, bat := range batches {
- body, _ := ioutil.ReadFile(bat)
- if !bytes.Contains(body, []byte("\r\n")) {
- fmt.Printf("Windows batch file %s does not contain CRLF line termination.\nTry running git checkout src/*.bat to fix this.\n", bat)
- os.Exit(1)
+ // Ensure that the GOROOT/src/all.bat file exists and has strict CRLF line endings.
+ enforceBatchStrictCRLF(filepath.Join(runtime.GOROOT(), "src", "all.bat"))
+
+ // Walk the entire Go repository source tree (without GOROOT/pkg),
+ // skipping directories that start with "." and named "testdata",
+ // and ensure all .bat files found have exact CRLF line endings.
+ err := filepath.Walk(runtime.GOROOT(), func(path string, fi os.FileInfo, err error) error {
+ if err != nil {
+ return err
+ }
+ if fi.IsDir() && (strings.HasPrefix(fi.Name(), ".") || fi.Name() == "testdata") {
+ return filepath.SkipDir
+ }
+ if path == filepath.Join(runtime.GOROOT(), "pkg") {
+ // GOROOT/pkg is known to contain generated artifacts, not source code.
+ // Skip it to avoid false positives. (Also see golang.org/issue/37929.)
+ return filepath.SkipDir
+ }
+ if filepath.Ext(fi.Name()) == ".bat" {
+ enforceBatchStrictCRLF(path)
+ }
+ return nil
+ })
+ if err != nil {
+ log.Fatalln(err)
+ }
+}
+
+func enforceBatchStrictCRLF(path string) {
+ b, err := ioutil.ReadFile(path)
+ if err != nil {
+ log.Fatalln(err)
+ }
+ cr, lf := bytes.Count(b, []byte{13}), bytes.Count(b, []byte{10})
+ crlf := bytes.Count(b, []byte{13, 10})
+ if cr != crlf || lf != crlf {
+ if rel, err := filepath.Rel(runtime.GOROOT(), path); err == nil {
+ // Make the test failure more readable by showing a path relative to GOROOT.
+ path = rel
}
+ fmt.Printf("Windows batch file %s does not use strict CRLF line termination.\n", path)
+ fmt.Printf("Please convert it to CRLF before checking it in due to golang.org/issue/37791.\n")
+ os.Exit(1)
}
}